4

我想知道是否有任何方法可以在部署在多個服務器上的asp.net web應用程序上執行'鎖定',使用像MySQL Cluster這樣的分佈式服務器。鎖定服務器場(asp.net)

例如,以更新帳戶餘額的經典示例爲例。沒有兩個請求應該同時更新相同的帳戶餘額。例如:

成員1個的帳戶餘額是100

  • 請求A訪問服務器1至100加至構件的天平1
  • 請求B訪問服務器2至50添加到成員的平衡1

因此請求A將餘額從100更新爲200並保存。
請求B將餘額更新爲150,並保存。

這些都在同一時間發生的準確,從而失去了信息,最終的結果應該是250

一個人怎麼可以鎖定,從而請求B將不得不等待,直到請求A完成,直到它檢索餘額。如果它是一個單獨的進程,這可以通過應用程序範圍的鎖來實現。但是,由於存在多個獨立進程,因此對於服務器1來說這不起作用,因此它不會被鎖定,也不能對服務器2執行任何想法或最佳實踐。

+0

這是現代基於雲的應用程序中的典型問題。它真的取決於數據庫。如果您的數據庫支持交易,請使用它們!如果你想得到一般的想法,你應該檢查出'兩階段提交協議'作爲開始:http://en.wikipedia.org/wiki/Two-phase_commit_protocol – Nappy 2011-12-21 14:50:45

回答

4

這就是交易的目的。

TransactionScope中包含需要原子化的操作,將它們註冊到明確的事務中。

這並不能完全解決陳舊數據的問題,因爲如果其他併發用戶正在使用舊值值進行更新,則一旦交易完成,您仍然有問題。

解決方案是使用表中每當行更改時都會更改的字段 - 在SQL Server 2008中,這是rowversion類型。

如果rowversion未更改,則只更新該行 - 如果已更改,則通知用戶並在不進行更新的情況下恢復當前值。

+0

我使用NHibernate作爲一個ORM解決方案。無論如何,你可以進行檢查,以便如果對象的'版本'發生了變化,它會拋出一個錯誤,然後應用程序可以捕獲該錯誤,並基本上重新啓動該進程,直到該版本尚未更改? – 2011-12-21 15:51:51

+0

@KarlCassar - 我不知道nHibernate足以告訴你。 – Oded 2011-12-21 15:55:51

+0

如果您定義版本列/屬性,則nhibernate將引發異常「行由另一事務更新」。 – iceburg 2016-03-29 04:05:06

1

在我創建的ORM中,我實現了一個鎖定機制。每種類型的實體(如Product,Customer等)都有兩個附加字段:'LockedBy(int)'和'LockedAt(datetime)'。

LockedBy包含鎖定實體的用戶的ID,lockedAt包含它被鎖定的時間戳。

因此,當用戶想要開始編輯實體,代碼都會經歷這個過程:

獲取從DB實體,「1」是產品ID

Product p = new Product(1); 

鎖定實體當前登錄的用戶

entity.Lock(); 

保存/提交實體到數據庫,保存()調用LockCheck()如果登錄的用戶有權保存實體返回true。

entity.Save(); 

用戶有權保存實體,如果:

(LockedBy < 0 || LockedBy == LoggedInUser.UserID || LockedAt < DateTime.Now.AddMinutes(-30)) 

注:用戶可以編輯這些被鎖定在30分鐘前的實體。如果另一個用戶打開了該實體(在編輯屏幕中),那麼每隔15分鐘它會彈出並詢問用戶是否仍然在那裏,如果是,它會執行一個請求,將LockedAt增加到Now(如滾動鎖)

此時沒有其他用戶可以編輯此實體!

代碼/用戶可以自由地儘可能多地希望一旦用戶停止編輯代碼編輯這個實體可以肯定,它並沒有改變它背後回來:)

電話:

entity.Unlock() 

然後

entity.Save() 

這則解放了實體供其他用戶編輯

+0

然後我注意到這是超過6個月大:/ – Metalstorm 2012-06-27 16:46:37

1

這是像Redis' pub/sub mechanism這樣的系統可以幫助您的地方。它本質上是一種向訂閱者(其他負載均衡的服務器)發送消息以讓他們知道事件已經發生的方式。 ServiceStack Redis client已完全支持這一點。