2017-02-03 134 views
0

即时通讯使用spring开发一个简单的休息应用程序。(春季)JPA /休眠奇怪的行为

我想实现一个使用Spring的@Scheduled注释周期性运行的方法。 我有一个方法从外部api获取数据并将其存储到数据库(Spring Jpa Repositories,扩展CrudRepositry)。我拥有的实体是公司和报告(公司有许多报告)。

遇到的问题IM是这样的:

要开始我打电话从控制器更新方法(简单的测试),但现在我想从我的调度类调用它,所以它执行自身。但是,当我移动代码(不修改的话),并从shceduler其称为我得到这个异常:

org.springframework.dao.InvalidDataAccessApiUsageException: detached entity passed to persist: Models.Company; nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: Models.Company 

当我打电话从控制器的方法,这并没有发生,我不知道为什么它现在。

这是使用在这两种情况下的代码IM:

ReportsManager reportsManager = new ReportsManager(); 
    reportsManager.updateReports(resultRepository, companyRepository.findAll()); 

里面的updateReports方法我做这样的事情:

List<BasicReport> resultsList = new ArrayList<>(); 

遍历公司的名单和创建报表的对象:

BasicReport currentResult = new BasicReport(); 
    currentResult.setReportName(request.getReportName()); 
    currentResult.setCompany(request.getCompany()); 
    resultsList.add(currentResult); 

然后我就保存列表其他地方:

repository.save(currentResults); 

werid的事情是,我在这两种情况下使用EXACT相同的代码,并得到不同的结果。 任何想法? 谢谢

编辑:在阅读@ user152468评论和@Dries S我现在增加了一个@Transactional注释到我的调度类和它的工作奇迹。 我猜@transactinal批注将EntityManager绑定到线程。 谢谢。

+0

我相信'@ scheduled'注释在spring'@ transactional'注释中不能很好地发挥作用。 Spring从这些类中构建代理,并且可能无法在同一个方法上处理两个注释。 – user152468

+0

虽然 – Juan

+0

我没有使用@transactional注释,但如果使用@RestController或类似的东西,它可能是隐含的。 – user152468

回答

0

如果从控制器使用,您可能有一个开放实体管理器在视图中的模式,在您的请求正在运行并生成报告的整个时间段内打开EntityManager

从您的计划方法运行时,您可能不会将您使用的EntityManager绑定到当前线程,因此在您的方法运行的整个过程中它都不会打开并生成报告。这意味着它会按需打开(即在你的DAO代码中),但会在从该方法返回时关闭,导致实体分离。

尝试使用TransactionSynchronisationManagerbindResource函数,它提供了一个EntityManagerHolder的实例。基本上OpenEntityManagerInViewInterceptor是做什么的,你可以查看源代码,并创建一个类似的方法,它在89行左右。