简体   繁体   English

@Scheduled + Hibernate -> LazyInitializationException

[英]@Scheduled + Hibernate -> LazyInitializationException

I am under Spring Boot 2.0.5, using Spring Data JPA我在 Spring Boot 2.0.5 下,使用 Spring Data JPA

I have a class such as this one (for the sake of understanding):我有一个这样的类(为了理解):

@Component
public class Synchronizer {

    @Autowired
    private MyService myService; 

    @Transactional
    public void synchronizeAuto() {
        List<MyTest> tests = myService.getTests();
        tests.get(0).getMyLazyObject().getName();
    }
}

The configuration is in here (there are other config files that I omitted):配置在这里(我省略了其他配置文件):

@Configuration
@EnableAsync
@EnableScheduling
@EnableTransactionManagement
public class SpringAsyncConfiguration implements AsyncConfigurer, SchedulingConfigurer {

    @Autowired
    private AppConfigProperties appConfigProperties;

    @Autowired
    private Synchronizer synchronizer;

    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(appConfigProperties.getThreadpoolCorePoolSize());
        executor.setMaxPoolSize(appConfigProperties.getThreadpoolMaxPoolSize());
        executor.setQueueCapacity(appConfigProperties.getThreadpoolQueueCapacity());
        executor.setThreadNamePrefix("threadPoolExecutor-");
        executor.initialize();
        return executor;
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new AsyncExceptionHandler();
    }

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.addCronTask(new Runnable() {

            @Override
            @Transactional
            public void run() {
                synchronizer.synchronizeAuto();
            }

        }, appConfigProperties.getCronExpression());
    }
}

The class MyService calls a Spring JPA repository to get all the "Test" instances MyService 类调用 Spring JPA 存储库以获取所有“测试”实例

A "Test" instance has a lazy loading (MyLazyObject) “测试”实例具有延迟加载 (MyLazyObject)

Anyway, everything works like a charm if I call the method from my controller.无论如何,如果我从控制器调用该方法,一切都会像魅力一样。

When it is run from the scheduler, I get the following error:当它从调度程序运行时,我收到以下错误:

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.tinea.apix.service.model.entity.apim.APIManagerEntity.synchroHistory, could not initialize proxy - no Session

Any idea?任何的想法?

Due to the use of the configureTasks which is called at configuration time, the Syncronizer is created very early.由于使用的configureTasks这就是所谓在配置时, Syncronizer的建立是非常早。 So early that it isn't eligible for proxy creation/post processing anymore.太早了,它不再有资格进行代理创建/后处理。 Which in turn leads to, at least the task, to use an unproxied instance and not having @Transactional applied.这反过来又导致,至少是任务,使用未经代理的实例,而不是应用@Transactional

Instead you should use an @Scheduled annotation together with the cronString property to resolve it the same way as you do now.相反,您应该将@Scheduled注释与cronString属性一起使用,以与现在相同的方式解决它。

@Scheduled(cron="@appConfigProperties.cronExpression")

The @ symbol in a SpEL expression indicates that a bean with the given name should be resolved. SpEL 表达式中的@符号表示应该解析具有给定名称的 bean。

@Scheduled(cron = "0 30 17 * * ?")

否则我们也可以这样使用

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM