我有一个JPA @Entity,其中@Id定义为
private UUID id;
@Id
@Column(name = "f_id")
@GeneratedValue(generator = "system-uuid")
@Type(type = "pg-uuid")
public UUID getId() {
return id;
}
和@Version字段定义为
private Timestamp lastModified;
@Version
@Column(name = "f_lastmodified")
@Attribute(required = false)
public Timestamp getLastModified() {
return lastModified;
}
postgres中的结果列(由hibernate使用create-drop生成)是“没有时区的时间戳”。 此类用于在postgres上运行的应用程序。删除实体时,我使用以下代码:
public T delete(UUID id) {
log.debug("deleting entity {}", id);
EntityManager em = ... //get from somewhere
em.flush(); //make sure we're in sync with DB
T object = em.find(getClassType(), id); //get latest version
if (object == null) {
throw new IllegalStateException("could not find an entity with id "+id);
}
em.refresh(object);
em.remove(object);
em.flush();
return object;
}
它曾经是一个更简单的查找(类型,id)+删除,但我添加了一些额外的绒毛试图让它工作。问题是上面的代码不起作用。日志中显示的错误是:
08:25:15,940 INFO [STDOUT] Hibernate:
08:25:15,950 INFO [STDOUT] delete
08:25:15,950 INFO [STDOUT] from
08:25:15,950 INFO [STDOUT] dpa.filesystem_status
08:25:15,950 INFO [STDOUT] where
08:25:15,950 INFO [STDOUT] f_id=?
08:25:15,960 INFO [STDOUT] and f_lastmodified=?
08:25:45,123 ERROR [org.hibernate.event.def.AbstractFlushingEventListener] Could not synchronize database state with session: org.hibernate.StaleObjec
tStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [FilesystemStatus#78c839f0-0b12-4df6-b9ec-ac1e52e9b1f1]
at org.hibernate.persister.entity.AbstractEntityPersister.check(AbstractEntityPersister.java:1950) [:3.6.1.Final]
at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:2710) [:3.6.1.Final]
at org.hibernate.persister.entity.AbstractEntityPersister.delete(AbstractEntityPersister.java:2911) [:3.6.1.Final]
经过一些调试后,我认为我找到了问题的根本原因:我试图删除的实体在版本字段中有NULL。 hibernate为删除构建一个准备好的语句(打印在上面的日志片段中),正确设置id,然后为版本字段设置NULL(逻辑上也正确)。执行此操作的hibernate代码位于BasicBinder.java第78行(hibernate core 3.6.1)
st.setNull( index, sqlDescriptor.getSqlType() );
第二个参数在运行时解析为93。最终,运行预准备语句导致0行被删除,而休眠假定它是因为“f_lastmodified =?”部分没有匹配并决定某人必须在其间提交不同的时间戳(==陈旧的实体传递给删除)。事实并非如此。
我如何从这里继续?
更具体地说:
1.我怎么知道93是否是传递给setNull()的正确sql类型?我在哪里可以找到“正确”的SQL类型表?它是特定于DB的(意思是我应该查看postgres文档)还是一些JDBC标准?
2.我该如何解决这个问题?我不能保证一个无空的@Version专栏,所以我需要这个场景才能工作
3.这是我错过的已知hibernate / postgresql-jdbc-driver问题吗?
我在win7 x64上使用jdk 1.6u24 x64,jboss 6.1-snapshot,hibernate 3.6.1.final,postgres 9.0,postgres jdbc4 driver 9.0-801
答案 0 :(得分:2)
由于第二点,您将无法使用@Version,因为版本列必须具有值。
2)我该如何解决这个问题? 我无法保证无效的@Version列,所以我需要这个场景才能工作
为了避免这种情况,您需要为版本控制创建自己的解决方案,或者需要为该列分配默认值。 有一个问题,我假设你的应用程序没有生成带有null版本的行,这是正确的吗?