2012-09-01 51 views
2

我有一個春季計劃作業(@Scheduled),根據數據庫中的收件人列表從我的系統發送電子郵件。Hibernate春季計劃作業中的惰性初始化異常

該方法用@Scheduled註釋標註,它從另一個界面調用方法,界面中的方法用@Transactional註釋標註。

現在,當我手動調用預定方法時,它完美地工作。但是當這個方法被Spring調度器調用時,我在實現上述接口的方法中得到了LazyInitFailed異常。

我在做什麼錯?

代碼:

調度的方法,包括:

@Component 
public class ScheduledReportsSender { 

    public static final int MAX_RETIRES = 3; 
    public static final long HALF_HOUR = 1000 * 60 * 30; 

    @Autowired 
    IScheduledReportDAO scheduledReportDAO; 

    @Autowired 
    IDataService dataService; 

    @Autowired 
    IErrorService errorService; 

    @Scheduled(cron = "0 0 3 ? * *") // every day at 2:10AM 
    public void runDailyReports() { 
     // get all daily reports 
     List<ScheduledReport> scheduledReports = scheduledReportDAO.getDaily(); 
     sendScheduledReports(scheduledReports); 
    } 

    private void sendScheduledReports(List<ScheduledReport> scheduledReports) { 
     if(scheduledReports.size()<1) { 
      return; 
     } 
     //check if data flow ended its process by checking the report_last_updated table in dwh 
     int reportTimeId = scheduledReportDAO.getReportTimeId(); 
     String todayTimeId = DateUtils.getTimeid(DateUtils.getTodayDate()); 
     int yesterdayTimeId = Integer.parseInt(DateUtils.addDaysSafe(todayTimeId, -1)); 
     int counter = 0; 

     //wait for time id to update from the daily flow 
     while (reportTimeId != yesterdayTimeId && counter < MAX_RETIRES) { 
      errorService.logException("Daily report sender, data not ready. Will try again in one hour.", null, null, null); 
      try { 
       Thread.sleep(HALF_HOUR); 
      } catch (InterruptedException ignore) {} 
      reportTimeId = scheduledReportDAO.getReportTimeId(); 
      counter++; 
     } 

     if (counter == MAX_RETIRES) { 
      MarketplaceServiceException mse = new MarketplaceServiceException(); 
      mse.setMessage("Data flow not done for today, reports are not sent."); 
      throw mse; 
     } 

     // get updated timeid 
     updateTimeId(); 

     for (ScheduledReport scheduledReport : scheduledReports) { 
      dataService.generateScheduledReport(scheduledReport); 
     } 
    } 

} 

調用的接口:

public interface IDataService { 

    @Transactional 
    public void generateScheduledReport(ScheduledReport scheduledReport); 
} 

實施(高達異常的線):

@Service 
public class DataService implements IDataService { 

public void generateScheduledReport(ScheduledReport scheduledReport) { 

     // if no recipients or no export type - return 
     if(scheduledReport.getRecipients()==null || scheduledReport.getRecipients().size()==0 || scheduledReport.getExportType() == null) { 
      return; 
     } 
} 
} 

Stack tr王牌:

ERROR: 2012-09-01 03:30:00,365 [Scheduler-15] LazyInitializationException.<init>(42) | failed to lazily initialize a collection of role: com.x.model.scheduledReports.ScheduledReport.recipients, no session or session was closed 
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.x.model.scheduledReports.ScheduledReport.recipients, no session or session was closed 
     at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:383) 
     at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:375) 
     at org.hibernate.collection.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:122) 
     at org.hibernate.collection.PersistentBag.size(PersistentBag.java:248) 
     at com.x.service.DataService.generateScheduledReport(DataService.java:219) 
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
     at java.lang.reflect.Method.invoke(Method.java:616) 
     at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:309) 
     at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183) 
     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150) 
     at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110) 
     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 
     at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202) 
     at $Proxy208.generateScheduledReport(Unknown Source) 
     at com.x.scheduledJobs.ScheduledReportsSender.sendScheduledReports(ScheduledReportsSender.java:85) 
     at com.x.scheduledJobs.ScheduledReportsSender.runDailyReports(ScheduledReportsSender.java:38) 
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
     at java.lang.reflect.Method.invoke(Method.java:616) 
     at org.springframework.util.MethodInvoker.invoke(MethodInvoker.java:273) 
     at org.springframework.scheduling.support.MethodInvokingRunnable.run(MethodInvokingRunnable.java:65) 
     at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:51) 
     at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:81) 
     at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471) 
     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334) 
     at java.util.concurrent.FutureTask.run(FutureTask.java:166) 
     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$101(ScheduledThreadPoolExecutor.java:165) 
     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:266) 
     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110) 
     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603) 
     at java.lang.Thread.run(Thread.java:636) 
ERROR: 2012-09-01 03:30:00,366 [Scheduler-15] MethodInvokingRunnable.run(68) | Invocation of method 'runDailyReports' on target class [class com.x.scheduledJobs.ScheduledReportsSender] failed 
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.x.model.scheduledReports.ScheduledReport.recipients, no session or session was closed 
     at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:383) 
     at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:375) 
     at org.hibernate.collection.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:122) 
     at org.hibernate.collection.PersistentBag.size(PersistentBag.java:248) 
     at com.x.service.DataService.generateScheduledReport(DataService.java:219) 
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
     at java.lang.reflect.Method.invoke(Method.java:616) 
     at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:309) 
     at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183) 
     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150) 
     at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110) 
     at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) 
     at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202) 
     at $Proxy208.generateScheduledReport(Unknown Source) 
     at com.x.scheduledJobs.ScheduledReportsSender.sendScheduledReports(ScheduledReportsSender.java:85) 
     at com.x.scheduledJobs.ScheduledReportsSender.runDailyReports(ScheduledReportsSender.java:38) 
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
     at java.lang.reflect.Method.invoke(Method.java:616) 
     at org.springframework.util.MethodInvoker.invoke(MethodInvoker.java:273) 
     at org.springframework.scheduling.support.MethodInvokingRunnable.run(MethodInvokingRunnable.java:65) 
     at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:51) 
     at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:81) 
     at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471) 
     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334) 
     at java.util.concurrent.FutureTask.run(FutureTask.java:166) 
     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$101(ScheduledThreadPoolExecutor.java:165) 
     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:266) 
     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110) 
     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603) 
     at java.lang.Thread.run(Thread.java:636) 

getReportTimeid實現:

@Override 
    public int getReportTimeId() { 
     Query query = super.entityManager.createNativeQuery("select timeid from lgdwh.report_last_updated order by timeid desc limit 1"); 
     return (Integer) query.getSingleResult(); 
    } 
+0

你能提供必要的代碼和堆棧跟蹤嗎? – JamesB

+0

嗨,詹姆斯,用代碼編輯問題。 –

+0

我會猜測問題在於爲每個ScheduledReport加載收件人集合。你可以發佈這個類的代碼嗎? – JamesB

回答

0

的問題是,我是在預定的類中提取從數據庫中的對象,並將其傳遞到的類,它在物體上的工作,我的解決辦法在將它傳遞給執行工作的類之前,將在預定的類中初始化該對象。

+1

您是否嘗試將'@ Transactional'添加到'runDailyReports'? – Pao

+0

@Paujo是的,它工作,如果我這樣做,但如果更新數據庫,查詢得到'reportTimeId'不刷新。 –

+0

你能顯示'getReportTimeId'嗎? – Pao