2011-05-24 54 views
1

我有一个JPA @Entity定义为冬眠无法与空删除@Entity @Version

private Timestamp lastModified; 

@Version 
@Column(name = "f_lastmodified") 
@Attribute(required = false) 
public Timestamp getLastModified() { 
    return lastModified; 
} 

在所得列定义为

private UUID id; 

@Id 
@Column(name = "f_id") 
@GeneratedValue(generator = "system-uuid") 
@Type(type = "pg-uuid") 
public UUID getId() { 
    return id; 
} 

一个@Id和@Version字段postgres(由使用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; 
} 

它曾经是一个简单的发现(类型,编号)+删除,但我已经添加了一些额外的绒毛设法得到它的工作。问题是上述代码不起作用。在日志中显示的错误是:

 
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(逻辑上也是正确的)。这样做的休眠代码是在BasicBinder.java 78行(休眠核心3.6.1)

st.setNull(index, sqlDescriptor.getSqlType()); 

第二个参数在运行时解析为93。最终,运行准备好的语句导致0行被删除,并且休眠状态假定它是因为“f_lastmodified =?”部分不匹配,并决定有人必须提交一个不同的时间戳之间(==陈旧的实体传递给删除)。这不是真的。

我该如何继续?

更具体地说:
1.我如何知道93是否是传递给setNull()的正确的sql类型?我在哪里可以找到一个“正确”的SQL类型表?它是数据库特定的(这意味着我应该去看看postgres文档)或一些JDBC标准?
2.我该如何解决该问题?我不能保证无空的@Version列,所以我需要这种情况下工作
3.这是一个已知的hibernate/postgresql-jdbc驱动程序问题,我错过了?

IM使用JDK对Win7的X64 1.6u24 64时,JBoss 6.1快照,休眠3.6.1.final,9.0 Postgres的,Postgres的jdbc4司机9.0-801

回答

2

您将无法使用,因为@Version第二点,如版本栏必须有一个值。

2)我该如何解决这个问题? 我无法机制保障自由空@Version列,所以我需要这个场景的工作

为了规避这一点,你要么需要创建版本自己的解决方案,否则你会需要分配该列的默认值。 有一个问题,我认为具有空版本的行不是由您的应用程序生成的,这是正确的吗?

+0

正确,其外部应用程序 – radai 2011-05-29 08:16:56

+0

对不起,解决方案是“没有解决方案”...您需要编写自己的查询来更新实体,如果您使用它们,您可能需要禁用级联。我有一个处于类似情况的同事,他的团队决定使用ibatis,在顶层使用薄层而不是hibernate,因为这个和其他一些限制。 – Augusto 2011-05-29 19:15:43

+1

我已经提出这个作为一个休眠的bug,让我们希望它在未来的版本中得到修复: http://opensource.atlassian.com/projects/hibernate/browse/HHH-6259 – radai 2011-05-31 05:15:02