2009-08-04 164 views
6

我使用在ASP.NET頁面下面的代碼創建一個記錄,然後計算記錄,以確保我未超過設定的限制,如果我有回滾事務。NHibernate的死鎖

using (var session = NhibernateHelper.OpenSession()) 
using (var transaction = session.BeginTransaction()) 
{ 
    session.Lock(mall, LockMode.None); 

    var voucher = new Voucher(); 
    voucher.FirstName = firstName ?? string.Empty; 
    voucher.LastName = lastName ?? string.Empty; 
    voucher.Address = address ?? string.Empty; 
    voucher.Address2 = address2 ?? string.Empty; 
    voucher.City = city ?? string.Empty; 
    voucher.State = state ?? string.Empty; 
    voucher.Zip = zip ?? string.Empty; 
    voucher.Email = email ?? string.Empty; 
    voucher.Mall = mall; 
    session.Save(voucher); 

    var issued = session.CreateCriteria<Voucher>() 
     .Add(Restrictions.Eq("Mall", mall)) 
     .SetProjection(Projections.Count("ID")) 
     .UniqueResult<int>(); 

    if (issued >= mall.TotalVouchers) 
    { 
     transaction.Rollback(); 
     throw new VoucherLimitException(); 
    } 

    transaction.Commit(); 
    return voucher; 
}   

但是,我遇到了很多的死鎖。我想這會發生,因爲我試圖計數表中的記錄,我只是執行了一個插入和一個鎖仍然保持在插入的行,導致死鎖。

  • 任何人都可以證實這一點?
  • 任何人都可以提出修復方案嗎?

我試着在最終查詢上調用SetLockMode(LockMode.None),但是這導致NullReferenceException,我找不出來。

編輯:如果我在保存對象之前運行查詢,它可以工作,但是我沒有完成驗證我的插入沒有超出限制的目標(在併發插入的情況下) 。

編輯:我發現,在session.BeginTransaction呼叫使用IsolationLevel.ReadUncommited解決了這個問題,但我沒有數據庫專家。這是適當的解決方案,或者我應該如何調整我的邏輯?

回答

3

該設計容易出現死鎖 - 通常(並非總是)一個連接不太可能自己死鎖,但是對同一個表進行插入和聚合的多個連接很可能會死鎖。這是因爲雖然從執行工作的連接的角度來看,一個事務中的所有活動看起來都是完整的 - 數據庫不會將事務鎖定在「自己的」記錄之外 - 來自OTHER事務的聚合查詢會嘗試鎖定整個桌子或其中的大部分,而那些會陷入僵局。

未提交讀是你在這種情況下的朋友,因爲它基本上是說「忽略鎖」,這在某種程度上將意味着違反你已經在各地設立了數據的規則。 I.E.表格中記錄的數量將不準確,您將根據不準確的數字採取行動。你數將返回10或13時,真正的答案是11

我最好的建議是重新排列你插入的邏輯,這樣你捕捉計的想法,不從字面上計數的行。你可以去幾個方向。我擁有的一個想法是:從字面上爲插入的憑證編號,並對序列進行限制。

  1. 請與列的順序表(我猜)MallID,nextVoucher,maxVouchers
  2. 種子該表與mallids,1,不管極限是每個商場
  3. 改變插入的邏輯這個僞代碼:
 
Begin Transaction 
Sanity check the nextVoucher for Mall in the sequence table; if too many exist abort 
If less than MaxVouchers for Mall then { 
    check, fetch, lock and increment nextVoucher 
    if increment was successful then use the value of nextVoucher to perform your insert. 
    Include it in the target table. 
} 
Error? Rollback 
No Error? Commit 

像這樣的順序表疼併發了一些,但我覺得不如在表不斷計數的行。一定要進行性能測試。 此外,[檢查,獲取,鎖定和增量]非常重要 - 您必須專門鎖定序列表中的行,以防止某些其他連接在分割之前在分割秒中使用相同的值。我知道這個SQL語法,但我恐怕我不是nHibernate專家。

對於讀取未提交的數據錯誤,檢查了這一點:http://sqlblog.com/blogs/merrill_aldrich/archive/2009/07/29/transaction-isolation-dirty-reads-deadlocks-demo.aspx(免責聲明:美林Aldrich公司是我:-)

0

2個問題:

  1. 如何頻繁地被刪除券
  2. 任何異議(超出純度)的 分貝電平觸發?
+0

從理論上講,憑證將永遠不會被刪除,甚至更新。此外,我傾向於避免性能方面的觸發器(儘管純度也很好)。 – Chris 2009-08-04 21:00:48

+0

但是讓我們說優惠券經常被刪除。確保通過插入優惠券的正確方法是什麼?我從來沒有超過任何限制? – Chris 2009-08-04 21:01:50