(Spring)JPA / Hibernate的奇怪行为

时间:2017-02-03 19:28:40

标签: java spring hibernate spring-mvc jpa

我正在使用spring开发一个简单的休息应用程序。

我正在尝试实现一个使用Spring的@Scheduled注释定期运行的方法。 我有一种方法从外部api获取数据并将其存储到数据库(Spring Jpa存储库,扩展CrudRepositry)。我拥有的实体是公司和报告(一家公司有很多报告)。

我遇到的问题是:

首先,我从控制器调用该更新方法(为了便于测试),但现在我想从我的调度类中调用它,以便它自己执行。但是当我移动代码(不修改它)和从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

当我从控制器调用该方法并且我不知道为什么现在这样做时,这不会发生。

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

    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);

令人担忧的是,我在两种情况下使用完全相同的代码并得到不同的结果。 有任何想法吗? 感谢

编辑:在阅读@ user152468评论和@Dries之后,我在我的调度程序类及其工作奇迹中添加了@Transactional注释。 我猜测@transactinal注释将EntityManager绑定到线程。 感谢。

1 个答案:

答案 0 :(得分:0)

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

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

尝试使用提供TransactionSynchronisationManager实例的EntityManagerHolder bindResource函数。基本上OpenEntityManagerInViewInterceptor做了什么,你可以查找源代码并创建一个类似的方法,它就在第89行附近。