6

我有一个春季计划作业 ( @Scheduled),它根据数据库中的收件人列表从我的系统发送电子邮件。

该方法使用注解进行@Scheduled注解,它从另一个接口调用方法,接口中的方法使用注解进行@Transactional注解。

现在,当我手动调用预定方法时,它可以完美运行。但是当弹簧调度程序调用该方法时,我在实现所述接口的方法中得到 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;
        }
}
}

堆栈跟踪:

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();
    }
4

1 回答 1

2

问题是我从调度类中的数据库中提取一个对象并将其传递给一个对对象起作用的类,我的解决方案是在将它传递给执行工作的类之前初始化调度类中的对象.

于 2012-09-01T09:36:19.300 回答