【问题标题】:JPA Entity Manager Merge with no changes in the objectJPA Entitymanager 合并而不更改对象
【发布时间】:2019-05-22 13:36:13
【问题描述】:

当对象没有变化时,我正在尝试使用实体管理器的合并方法来更新数据库中的对象。假设该行具有以下属性:

id             DECIMAL(11) NOT NULL,
name           CHAR(20) NOT NULL, 
lastModified   TIMESTAMP NOT NULL FOR EACH ROW ON UPDATE AS ROW CHANGE TIMESTAMP

假设我在数据库中有一个对象(我们称它为 Person),具有以下属性:

{id: 1, name: "example", lastModified: 2019-05-22 16:24:54.771}

所以 lastModified 属性是每次行发生变化时 db 都会更新的属性。

现在,当我首先获取对象,然后将人名更新为“example”(与数据库中已有的值相同),然后使用合并更新它时,lastModified 属性不会似乎在数据库中更新。即

Person person = em.find(Person.class, 1)
person.setName("example")
em.merge(person)

经过上述操作,lastModified 仍然是 2019-05-22 16:24:54.771(与之前相同)。现在,如果我会更改名称,即

Person person = em.find(Person.class, 1)
person.setName("new name")
em.merge(person)

所以现在 lastModified 也会更新。

对这个有帮助吗?有人可以解释一下为什么当没有对对象进行更改时该行不会更新? :) 谢谢!

【问题讨论】:

  • 当我们调用 JPA 合并(实体)时,如果对实体所做的任何更改将被持久化到数据库中,反之亦然。因为没有对 Person 对象进行任何更改(当您将相同的名称更新为 person 对象时)。因此,它不会将条目更新到数据库中。
  • 如果你想实现任何方式,你可以像这样更改 lastModifiedDate person.setLastmodifiedDate(new Date())。

标签: jpa entity


【解决方案1】:

当您使用merge 时,Hibernate 首先在您尝试合并的元组中运行 Select 语句。执行此选择以获取元组的最新状态,然后使用元组中已更改的数据在数据库中运行更新。

正如您在示例中所说,您没有更改任何数据,因为您正在尝试将名称更新为与以前相同的名称,因此 hibernate 不会对数据库运行任何更新。

您可以参考 Hibernate Dirty Checking Mechanism 了解更多信息。

如果您真的想在没有数据更改的情况下更新此列,则必须在应用程序层执行此操作,方法是在保存 Person 对象时手动设置:

person.setLastModified(LocalDateTime.now())

【讨论】:

  • 感谢马塞洛的澄清! :)
【解决方案2】:

只是对马塞洛回答的补充:

您应该只在“合并”持久上下文之外的数据时使用merge()。例如,当您从未链接到事务范围的 REST API 接收到 Person 对象时,您希望将其连接到上下文,然后将其保存在 EJB 中。

在您的代码中,删除 em.merge(person) 语句。当您通过代理使用set() 方法时,Hibernate/JPA 将检测到更改,并在后台生成 SQL 命令。

【讨论】:

    【解决方案3】:

    除了 Marcelo 的回答之外,您还可以使用锁强制更新实体。使用以下内容:

    em.lock(person, LockModeType.OPTIMISTIC_FORCE_INCREMENT)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-23
      • 2015-05-25
      • 1970-01-01
      • 2016-11-24
      • 1970-01-01
      • 1970-01-01
      • 2016-02-21
      • 1970-01-01
      相关资源
      最近更新 更多