问题描述
||
我有一个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;
}
它曾经是一个更简单的find(type,id)+ remove,但是我添加了一些额外的绒毛以使其正常工作。问题是上述代码无法正常工作。日志中显示的错误是:
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]
经过一些调试后,我认为我找到了问题的根本原因:我尝试删除的实体在version字段中为NULL。 hibernate为删除创建一个准备好的语句(在上面的日志代码段中显示),正确设置id,然后为版本字段设置NULL(在逻辑上也是正确的)。在BasicBinder.java第78行(休眠核心3.6.1)中执行此操作的休眠代码
st.setNull( index,sqlDescriptor.getsqlType() );
第二个参数在运行时解析为93。最终,运行prepared语句将导致0行被删除,并且由于\“ f_lastmodified =?\”部分不匹配,因此休眠假定它为休眠状态,并确定某人必须在两者之间提交不同的时间戳(==传递给删除的陈旧实体)。这不是真的。
我如何从这里继续?
进一步来说:
1.我怎么知道93是否是传递给setNull()的正确sql类型?在哪里可以找到\“正确\” sql类型的表?是特定于DB的(意味着我应该去看看postgres文档)还是某种JDBC标准?
2.我该如何解决该问题?我无法保证无空@Version列,所以我需要这种情况才能工作
3.这是我错过的已知的休眠/ postgresql-jdbc-driver问题吗?
我在win7 x64上使用jdk 1.6u24 x64,jboss 6.1快照,休眠3.6.1.final,postgres 9.0,postgres jdbc4驱动程序9.0-801
解决方法
由于第二点,您将无法使用@Version,因为version列必须具有值。
2)我该如何解决该问题?我无法保证无空的@Version列,所以我需要这种情况才能工作
为了避免这种情况,您需要创建自己的版本控制解决方案,或者需要为该列分配默认值。
一个问题,我假设您的应用程序未生成具有空版本的行,这是正确的吗?