【问题标题】:Why do I not see changes issued through an update query with Spring Data JPA?为什么我看不到通过 Spring Data JPA 的更新查询发出的更改?
【发布时间】:2014-04-27 07:45:43
【问题描述】:

我有以下服务:

@Service
public class CamelService {

    @Transactional
    public aCamelThing() {

          Camel camel = this.camelRepository.findOne(1);

          System.out.println(camel.getCamelName());  // prints "normalCamel"

          // simple hql set field 'camelName'
          int res = this.camelRepository.updateCamelName(1,"superCamel!");

          Camel camelWithNewName = this.camelRepository.findOne(1);

          System.out.println(camelWithNewName .getCamelName());  // prints "normalCamel" ?!?!?

    } 
}

知道如何实现第二个 println 将打印的目标:“superCamel!” ? (将第二次调用与新事务分开并不理想)。

【问题讨论】:

  • 不确定您的 updateCamelName 在做什么(可能发出 HQL 查询?)。但是您至少需要刷新您的更改并可能清除存储库,否则您将获得已检索的实体。另外,您为什么不简单地用名称更新camel 并存储它?!
  • 除了 M. Deinum 所说的 updateCamelName 还应该提交事务。方法是否用@Transactional注解
  • Deinum,我尝试了 camelRepository.flush() 但最后一次发现仍然没有带来新名称。为什么我不简单地更新对象?我的现实生活用例比我发布的要复杂得多,这只是为了简单起见。 Dhanush,该方法是事务性的,那么为什么要存储库呢?

标签: java spring jpa spring-data


【解决方案1】:

您看到它工作的原因很简单:JPA 被定义为以这种方式工作。

我假设您触发了updateCamelName(…) 的更新查询。 JPA 规范为更新和删除操作规定了以下内容:

持久化上下文与批量更新或删除的结果不同步。

在执行批量更新或删除操作时应该小心,因为它们可能会导致数据库和活动持久性上下文中的实体之间的不一致。一般来说,批量更新和删除操作只能在新的持久性上下文中的事务内执行,或者在获取或访问状态可能受此类操作影响的实体之前执行。

这意味着,如果您需要查看此类操作的更改,您需要执行以下操作:

  1. 在此操作后清除EntityManager Spring Data JPA 的@Modifying 注释有一个clearAutomatically 标志,默认为false。如果设置为 true,则调用查询方法将自动清除 EntityManager(顾名思义。谨慎使用它,因为它会有效地删除所有尚未刷新到数据库的待处理更改!
  2. EntityManager 重新获取实体的新实例。 在存储库上调用findOne(…) 似乎是一种合理的方法,因为这大致转换为EntityManager.find(…)。请注意,这可能仍会影响持久性提供程序上配置的二级缓存。

解决此问题的最安全方法是 - 正如规范所建议的那样 - 仅将更新查询用于批量操作,并默认回退到“加载实体、更改、合并”方法。

【讨论】:

    猜你喜欢
    • 2016-07-29
    • 2021-09-28
    • 1970-01-01
    • 2015-02-21
    • 2011-12-22
    • 2018-01-13
    • 1970-01-01
    • 2012-04-15
    • 1970-01-01
    相关资源
    最近更新 更多