2009-11-23 46 views
0

我在使用NHibernate異步保存到數據庫時遇到競爭條件問題。首先對數據庫的插入是異步完成的,其中唯一ID是自動生成的。在這個插入返回到主線程之前,這個持久化對象具有唯一的數據庫生成的id,該對象以某種方式更新。如果我調用session.Update,更新將失敗,因爲要更新的對象沒有id值。如果我調用SaveOrUpdate,它顯然會導致插入而不是更新,因爲我的實體的id字段等於unsaved-value屬性。希望這段代碼能夠使情況更加清晰:Nhibernate,多線程和競態條件

Entity entity = new Entity() 
//update some fields 
entity.PropertyTwo = "new value"; 
//dataObject as the database auto-generated Id 
//insert new row asynchronously in different thread 
Entity entity.Id = dao.save(entity.Clone()).Id 

//before the the entity is returned from the database, the entity might be updated 
entity.Property = 'new value'; 
//entity might be sent without an Id since the first asynch call has not returned yet. 
//update asynchronously in another thread 
Object dataObject = dao.Update(entity); //fails because Id is not set yet 

一種解決方案是在保存之前在代碼中生成唯一的ID。在這種情況下,應用程序管理唯一標識的增量,而不是數據庫。任何其他方式處理這個?

回答

1

看起來你可能會在單個NHibernate會話中創建多個線程。 NHibernate中的會話是不是線程安全的。你不應該在兩個併發線程中訪問同一個Session。嘗試在新線程中創建單獨的會話並查看它是否可以解決您的問題。

查看NHibernate documentation section 10.2

+0

不,我正在爲每個線程創建一個會話。如果在插入完成之前在實體上更新更新 – infinity 2009-11-24 18:56:17

+0

記住每個數據庫調用都發生在另一個線程上,所以如果在第二個線程上嘗試更新,然後插入在前一個線程上完成,則會出現競態條件錯誤。 – infinity 2009-11-24 19:02:12

+0

你能解釋爲什麼你要克隆實體對象並保存克隆?你可能已經試過了,但是如果你在同一個實體對象(無克隆)的所有線程中執行SaveOrUpdate(),那麼無論哪個線程首先插入,其他線程都會執行更新。這是否適合您的設計? – 2009-11-24 21:52:01

0

在調用update之前,您需要放置某種「等待插入完成」類型的邏輯。這是標準的多線程異步編程。

在多線程環境中,很可能在同一個對象上同時調用Insert和Update。你只需要確保底層代碼是足夠聰明到:

  1. 執行插入更新之前
  2. 等待插入到開始更新之前,

有許多不同的方式完成要做到這一點,他們都不一定比另一個更好。你在概念上需要一個鎖,你可以獲取,放棄和等待。

此外,這個問題與NHibernate沒有任何關係。多線程編程非常困難。如果可能的話,最好避免使用多線程,因爲複雜性很容易失控。