2010-02-17 57 views
4

以下代碼嘗試使用Spring + Hibernate將Item對象插入到數據庫。該項目有一個Integer ID字段作爲主鍵,以及一個受限於唯一約束的name列(簡化示例)。
我知道該項目的ID爲空(該項目是瞬態的),但插入可能仍然失敗,因爲名稱字段上的唯一約束。在失敗的插入後恢復Hibernate會話狀態

try { 
    getHibernateTemplate().save(myItem); 
    getHibernateTemplate().flush(); // exception thrown here if the name is not unique 
} 
catch (DataIntegrityViolationException e) { 
    Item itemFromDb = (Item) getHibernateTemplate() 
    .find("from Item item where item.name = ?", 
      myItem.getName()).get(0); 
    // 
    // copy some properties from myItem to itemFromDb 
    // 
    getHibernateTemplate.update (itemFromDb) 
} 

我需要這個代碼在多個項目運行一個循環,全部在一個事務中,這就是爲什麼我想,如果插入失敗發佈更新。

但是,插入失敗後,休眠會話處於一種奇怪的狀態,當我發出select語句從db獲取該項時,會引發原始異常。

我試過在插入失敗後使用session.evict(),但無濟於事。任何想法?

這是我在選擇失敗後在控制檯中看到的內容。 Hibernate在select語句上失敗,但仍然打印有關前一個插入語句的信息。

WARN [http-8080-1] hibernate.util.JDBCExceptionReporter (JDBCExceptionReporter.java:77) - SQL Error: 2627, SQLState: 23000 
ERROR [http-8080-1] hibernate.util.JDBCExceptionReporter (JDBCExceptionReporter.java:78) - Violation of UNIQUE KEY constraint 'unq_Item_name'. Cannot insert duplicate key in object 'items'. 
ERROR [http-8080-1] event.def.AbstractFlushingEventListener (AbstractFlushingEventListener.java:301) - Could not synchronize database state with session 
org.hibernate.exception.ConstraintViolationException: could not insert: [com.sample.Item] 
    at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71) 

P.S.請不要告訴我關於hibernate的saveOrUpdate方法,我知道它做了什麼。

+0

也許最好在插入/更新之前進行選擇? – 2010-02-17 15:34:09

回答

3

一旦拋出數據庫異常,Hibernate不保證會話的任何信息。你應該回滾。如果我瞭解Bozho的建議,他說你應該先從名稱欄中讀取以確保插入不會失敗。我感覺合理。

+0

你的回答不是很樂觀,但不幸的是我認爲這是正確的,尤其是有關會話狀態的部分。所以我是這樣標記的。 – Yoni 2010-02-20 17:29:49

+0

對不起,這是一個下跌。複合鍵會幫助你嗎?您可以包含主鍵和具有唯一性約束的鍵。我認爲生成的SQL仍然是相似的,但是您可能能夠簡化代碼,更好地使用二級緩存(不需要查詢緩存)等。 – ShabbyDoo 2010-02-21 18:47:04

1
getHibernateTemplate().merge(myItem); 

合併 - 給定對象的狀態複製到具有相同標識符的持久對象。如果當前沒有與會話關聯的持久實例,則會加載它。返回持久化實例。如果給定實例未保存,則保存一個副本並將其作爲新的持久實例返回。給定的實例不會與會話關聯。如果關聯使用cascade =「merge」進行映射,則此操作將級聯到關聯的實例。

+0

@Bozho,謝謝你的回覆。我的理解是,我需要在保存/更新之前選擇對象,並且我試圖避免出於性能原因。由於該項目是暫時的,合併會嘗試保存它,這是我已經做了(並失敗) – Yoni 2010-02-17 16:29:06

+0

如果它有一個標識符等於現有的東西,它會觸發我認爲的更新。 – Bozho 2010-02-17 16:33:11