休眠状态无法删除具有空@Version的@Entity

问题描述

|| 我有一个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列,所以我需要这种情况才能工作 为了避免这种情况,您需要创建自己的版本控制解决方案,或者需要为该列分配默认值。 一个问题,我假设您的应用程序未生成具有空版本的行,这是正确的吗?