2011-05-17 36 views
7

我遇到了一個問題。我有一個Hibernate應用程序,它將XML文件中的數據加載到併發模式的表中。某些部分數據可能相同,可能從不同的線程插入。每個線程都在自己的長時間交易中工作。有兩個或更多步驟嘗試提交事務時存在問題。例如兩個線程插入記錄到表城市,其中有名稱字段的限制。這意味着在flush()或commit()上發生ConstraintViolationException。我想自動處理這些衝突,並希望用舊的已插入對象替換新的問題對象。這可能嗎?我在Hibernate中查看saveOrUpdate()和樂觀版本控制。Hibernate併發插入

+0

您好,如果您將問題分享給您的解決方案,我會很高興。看起來下面是正確的答案,但簡單的解釋應該更方便。非常感謝。 – Javatar 2012-02-25 18:04:19

回答

1

我假設你使用MVCC-based DBMS之一。

如果事務隔離級別不高於READ COMMITTED,可以通過在插入新行之前發出一個查詢來檢查是否存在具有相同name的城市的查詢來降低衝突概率。

請注意,saveOrUpdate()不能幫助這裏,因爲name不是主鍵。還要注意,根本不能防止衝突(至少不使用某些DBMS特有的功能),因爲基本上它是write skew anomaly的示例,這在基於MVCC的DBMS中無法防止。另外,如果導入XML文件的原子性並不重要,則可以將長事務分解成幾個較短的事務,並且在違反約束的情況下簡單地重試它們。

+0

謝謝,分解交易是一個好主意。我認爲,在併發情況下,城市對象的存在並不能起作用。總會有碰撞的機會。同意saveOrUpdate()已經檢查過它。 – 2011-05-17 13:50:39

+0

對不起,您的意思是使用READ UNCOMMITTED並檢查存在?我認爲它可以幫助。至少未被記錄的記錄是在交易中共享的,並且在沒有記錄的會話中進行存在檢查並不昂貴。 – 2011-05-17 14:10:37

0

在這樣的情況下,我們使用'insertOrUpdate()'方法的約定和下面的一般流程。該交易是在返回時由'insertOrUpdate()'方法的調用者承諾的:

public MyHibernateObject insertOrUpdate(MyHibernateObject newObj, Session s) { 
    String name = newObj.getCityName(); 
    MyHibernateObject existingObj = getByCityName(name, s); 
    if (existingObj == null) { 
     s.saveOrUpdate(newObj); 
     return newObj; 
    } else { 
     existing.copyImportantFields(newObj); 
     s.saveOrUpdate(existing); 
     return existing; 
    } 
}