当对象中没有任何更改时,我正在尝试使用实体管理器的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也将更新。
对此有任何帮助吗?有人可以解释一下为什么对对象进行任何更改时行都不会更新吗? :)谢谢!
答案 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)