2011-05-24 55 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