JPA实体管理器合并,对象没有变化

时间:2019-05-22 13:36:13

标签: java jpa java-ee entity

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

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属性是数据库在每次行发生更改时都会更新的属性。

现在,当我首先获取对象,然后将人的名字更新为“ example”(与数据库中已有的值相同),然后使用merge对其进行更新时,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也将更新。

对此有任何帮助吗?有人可以解释一下为什么对对象进行任何更改时行都不会更新吗? :)谢谢!

3 个答案:

答案 0 :(得分:1)

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

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

有关休眠脏检查机制的更多信息,请阅读

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

person.setLastModified(LocalDateTime.now())

答案 1 :(得分:1)

只是Marcelo回答的补充:

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

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

答案 2 :(得分:0)

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

em.lock(person, LockModeType.OPTIMISTIC_FORCE_INCREMENT)