hibernate无法使用null @Version删除@Entity

时间:2011-05-24 06:13:58

标签: hibernate postgresql jpa

我有一个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

1 个答案:

答案 0 :(得分:2)

由于第二点,您将无法使用@Version,因为版本列必须具有值。

2)我该如何解决这个问题? 我无法保证无效的@Version列,所以我需要这个场景才能工作

为了避免这种情况,您需要为版本控制创建自己的解决方案,或者需要为该列分配默认值。 有一个问题,我假设你的应用程序没有生成带有null版本的行,这是正确的吗?