2010-11-23 73 views
1

跟進this other questionNHibernate - 悲觀鎖定不起作用

我試圖對上述問題中描述的併發問題實施悲觀鎖定(請隨時添加到該問題)。但它不適合我。

我做了一個非常簡單的測試:我有兩個獨立的站點運行,都增加了一個計數器500次。我同時運行它們。最後,我希望我的表格中的某一列有你猜的值1000.

這裏是代碼。當然不是生產代碼,但是測試代碼與否,它應該仍然有效,對吧?

for (int i = 0; i < 500; i++) 
{ 
    var tx = this.userRepo.Session.BeginTransaction(); 
    var user = this.userRepo.GetById(42); 
    user.Counter++; 
    userRepo.Save(user); 
    tx.Commit(); 
} 

GetById方法使用LockMode.Upgrade:

public T GetById(int id) 
{ 
    T obj = Session.Get<T>(id, LockMode.Upgrade); 
    return obj; 
} 

現在,使用NHProfiler我看到下面的SQL語句:

SELECT Id FROM 'User' WHERE Id = 42 for update

但結果卻是圍繞一個價值,因此大約有一半的更新因併發性而丟失。我究竟做錯了什麼?我在這個測試中禁用了二級緩存。我使用錯誤的鎖定模式嗎?我應該指定一個等值線嗎?還要別的嗎?提前致謝。

編輯: FluentNhibernate配置:

Fluently.Configure() 
.Database(MySQLConfiguration.Standard.ConnectionString(connectionstring)) 
.Mappings(m => assemblyTypes.Select(t => t.Assembly).ToList().ForEach(a => m.FluentMappings.AddFromAssembly(a))) 
.ExposeConfiguration(c => c.Properties.Add("hbm2ddl.keywords", "none")); 
+0

你可以發佈你的Nhibernate配置代碼嗎? – UpTheCreek 2010-11-23 08:41:23

+0

@UpTheCreek:使用FluentNH,不知道你想看到什麼,但我包括它 – Razzie 2010-11-23 09:12:32

回答

0

對於LockMode.Upgrade工作,所有交易都被封閉在一個事務,因爲什麼LockMode.Upgrade確實是其鎖定到當前事務。

您的問題很可能是由於未包含在交易中的陳述所致。

樂觀鎖定不適用於單個語句,而適用於彼此分離的多個事務。舉例:

  1. 開始交易;

  2. 通過Id = 42獲取記錄;

  3. 結束交易。

然後,在交易之外,增加Counter

之後:

  1. 開始事務;

  2. 通過Id = 42獲取記錄;

  3. 檢查計數器是否與第一筆交易中收到的價值沒有變化;

    a。如果它沒有改變,用增加的值更新計數器;

    b。如果它已更改,則處理更改後的值。

  4. 結束交易。

樂觀鎖意味着你「希望」的Counter尚未兩次交易之間的變化,處理情況已經改變的情況下。通過悲觀鎖定,您可以確保所有更改都在單個事務中完成,並鎖定所有必需的記錄。

B.t.w .:檢查機制(是否Counter已同時更改)可以由NHibernate自動處理。