在 Java 11 上将 LocalDateTime 作为 @Version 字段与 Hibernate 5.3 / JPA 2.2 一起使用会导致 StaleObjectStateException
Using LocalDateTime as @Version field with Hibernate 5.3 / JPA 2.2 on Java 11 leads to StaleObjectStateException
考虑一个名为 Template
的实体,其中包含一个字段:
@Version
@Column(name = "LAST_UPDATE", nullable = false)
private LocalDateTime lastUpdate; // Java 8's class
支持的 Oracle 数据库字段是 TIMESTAMP
。
现在执行以下代码:
// get EntityManager, start transaction
final var t = new Template();
t.setName("new template");
t.setSubject("subject");
em.persist(t);
t.setSubject("subject - mod");
tx.commit();
导致抛出异常:
Caused by: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [Template#169]
at org.hibernate.persister.entity.AbstractEntityPersister.check(AbstractEntityPersister.java:2525)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3357)
at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:3231)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3632)
at org.hibernate.action.internal.EntityUpdateAction.execute(EntityUpdateAction.java:146)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:478)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:356)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1453)
... 59 common frames omitted
如果我将 lastUpdate
的类型更改为 java.sql.Timestamp
,代码将正常运行。可能是什么问题?
虽然文档中没有明确说明,但我认为 Hibernate 支持这种类型作为 @Version 字段。
此处提供测试用例:https://github.com/imeszaros/jooby-hbm-localdatetime
记录一下:Oracle的TIMESTAMP
类型默认精度为6,只能存储毫秒。
Java 的 LocalDateTime
但是可能有纳秒,因此您需要在数据库中使用 TIMESTAMP(9)
才能在不损失精度的情况下存储值。
考虑一个名为 Template
的实体,其中包含一个字段:
@Version
@Column(name = "LAST_UPDATE", nullable = false)
private LocalDateTime lastUpdate; // Java 8's class
支持的 Oracle 数据库字段是 TIMESTAMP
。
现在执行以下代码:
// get EntityManager, start transaction
final var t = new Template();
t.setName("new template");
t.setSubject("subject");
em.persist(t);
t.setSubject("subject - mod");
tx.commit();
导致抛出异常:
Caused by: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [Template#169]
at org.hibernate.persister.entity.AbstractEntityPersister.check(AbstractEntityPersister.java:2525)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3357)
at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:3231)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:3632)
at org.hibernate.action.internal.EntityUpdateAction.execute(EntityUpdateAction.java:146)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:478)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:356)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39)
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1453)
... 59 common frames omitted
如果我将 lastUpdate
的类型更改为 java.sql.Timestamp
,代码将正常运行。可能是什么问题?
虽然文档中没有明确说明,但我认为 Hibernate 支持这种类型作为 @Version 字段。
此处提供测试用例:https://github.com/imeszaros/jooby-hbm-localdatetime
记录一下:Oracle的TIMESTAMP
类型默认精度为6,只能存储毫秒。
Java 的 LocalDateTime
但是可能有纳秒,因此您需要在数据库中使用 TIMESTAMP(9)
才能在不损失精度的情况下存储值。