ASP.NET 併發控制

當多個用戶試圖同時修改數據時,須要創建控制機制來防止一個用戶的修改對同時操做的其餘用戶所做的修改產生不利的影響。處理這種狀況的系統叫作「併發控制」。html

併發控制的類型

一般,管理數據庫中的併發有三種常見的方法:

保守式併發控制 - 在從獲取記錄直到記錄在數據庫中更新的這段時間內,該行對用戶不可用。
開放式併發控制 - 只有當實際更新數據時,該行纔對其餘用戶不可用。更新將在數據庫中檢查該行並肯定是否進行了任何更改。若是試圖更新已更改的記錄,則將致使併發衝突。
最後的更新生效 - 只有當實際更新數據時,該行纔對其餘用戶不可用。可是,不會將更新與初始記錄進行比較;而只是寫出記錄,這可能就改寫了自上次刷新記錄後其餘用戶所進行的更改。數據庫

保守式併發

保守式併發一般用於兩個目的。第一,在某些狀況下,存在對相同記錄的大量爭用。在數據上放置鎖所費的成本小於發生併發衝突時回滾更改所費的成本。安全

在事務過程當中不宜更改記錄的狀況下,保守式併發也很是有用。庫存應用程序即是一個很好的示例。假定有一個公司表明正在爲一名潛在的客戶檢查庫存。您一般要鎖定記錄,直到生成訂單爲止,這一般會將該項標記爲「已訂購」狀態並將其從可用庫存中移除。若是未生成訂單,則將釋放該鎖,以便其餘檢查庫存的用戶獲得準確的可用庫存計數。數據結構

可是,在斷開的結構中沒法進行保守式併發控制。鏈接打開的時間只夠讀取數據或更新數據,所以不能長時間地保持鎖。此外,長時間保留鎖的應用程序將沒法進行伸縮。併發

注意 若是基礎數據源支持事務,則能夠經過在事務中更新數據來模擬保守式併發。有關更多信息,請參見 ADO.NET 中的事務。spa

開放式併發

在開放式併發中,只有在訪問數據庫時才設置並保持鎖。這些鎖將防止其餘用戶在同一時間更新記錄。除了進行更新這一確切的時刻以外,數據始終可用。有關更多信息,請參見開放式併發。code

當試圖更新時,已更改行的初始版本將與數據庫中的現有行進行比較。若是二者不一樣,更新將失敗,並引起併發錯誤。這時,將由您使用所建立的業務邏輯來協調這兩行。htm

最後的更新生效

當使用「最後的更新生效」時,不會對初始數據進行檢查,而只是將更新寫入數據庫。很明顯,可能會發生如下狀況:對象

用戶 A 從數據庫獲取一項記錄。
用戶 B 從數據庫獲取相同的記錄,對其進行修改,而後將更新後的記錄寫回數據庫。
用戶 A 修改「舊」記錄並將其寫回數據庫。
在上述狀況中,用戶 A 永遠也不會看到用戶 B 做出的更改。若是您計劃使用併發控制的「最後的更新生效」方法,則要確保這種狀況是能夠接受的。blog

ADO.NET 和 Visual Studio .NET 中的併發控制

由於數據結構基於斷開的數據,因此 ADO.NET 和 Visual Studio .NET 使用開放式併發。所以,您須要添加業務邏輯,以利用開放式併發解決問題。

若是您選擇使用開放式併發,則能夠經過兩種常規的方法來肯定是否已發生更改:版本方法(實際版本號或日期時間戳)和保存全部值方法。

版本號方法

在版本號方法中,要更新的記錄必須具備一個包含日期時間戳或版本號的列。當讀取該記錄時,日期時間戳或版本號將保存在客戶端。而後,將對該值進行部分更新。

處理併發的一種方法是僅當 WHERE 子句中的值與記錄上的值匹配時才進行更新。該方法的 SQL 表示形式爲:

UPDATE Table1 SET Column1 = @newvalue1, Column2 = @newvalue2
WHERE DateTimeStamp = @origDateTimeStamp
或者,可使用版本號進行比較:

UPDATE Table1 SET Column1 = @newvalue1, Column2 = @newvalue2
WHERE RowVersion = @origRowVersionValue
若是日期時間戳或版本號匹配,則代表數據存儲區中的記錄未被更改,而且能夠安全地使用數據集中的新值對該記錄進行更新。若是不匹配,則將返回錯誤。您能夠編寫代碼,在 Visual Studio .NET 中實現這種形式的併發檢查。您還必須編寫代碼來響應任何更新衝突。爲了確保日期時間戳或版本號的準確性,您須要在表上設置觸發器,以便在發生對行的更改時,對日期時間戳或版本號進行更新。

保存全部值方法

使用日期時間戳或版本號的替代方法是在讀取記錄時獲取全部字段的副本。ADO.NET 中的 DataSet 對象維護每一個修改記錄的兩個版本:初始版本(最初從數據源中讀取的版本)和修改版本(表示用戶更新)。當試圖將記錄寫回數據源時,數據行中的初始值將與數據源中的記錄進行比較。若是它們匹配,則代表數據庫記錄在被讀取後還沒有通過更改。在這種狀況下,數據集中已更改的值將成功地寫入數據庫。

對於數據適配器的四個命令(DELETE、INSERT、SELECT 和 UPDATE)來講,每一個命令都有一個參數集合。每一個命令都有用於初始值和當前值(或修改值)的參數。

注意 因爲不存在初始記錄,添加新記錄(INSERT 命令)只須要當前值;移除記錄(DELETE 命令)只須要使用初始值來定位要刪除的記錄。
如下示例顯示一個數據集命令的命令文本,該命令更新一個典型的客戶表。該命令是爲動態 SQL 和開放式併發而指定的。

UPDATE Customers SET CustomerID = @currCustomerID, CompanyName = @currCompanyName, ContactName = @currContactName,
ContactTitle = currContactTitle, Address = @currAddress, City = @currCity,
PostalCode = @currPostalCode, Phone = @currPhone, Fax = @currFax
WHERE (CustomerID = @origCustomerID) AND (Address = @origAddress OR @origAddress IS NULL AND Address IS NULL) AND (City = @origCity OR @origCity IS NULL AND City IS NULL)
AND (CompanyName = @origCompanyName OR @origCompanyName IS NULL AND CompanyName IS NULL) AND (ContactName = @origContactName OR @origContactName IS NULL AND ContactName IS NULL) AND (ContactTitle = @origContactTitle OR @origContactTitle IS NULL AND ContactTitle IS NULL)
AND (Fax = @origFax OR @origFax IS NULL AND Fax IS NULL) AND (Phone = @origPhone OR @origPhone IS NULL AND Phone IS NULL) AND (PostalCode = @origPostalCode OR @origPostalCode IS NULL AND PostalCode IS NULL);
SELECT CustomerID, CompanyName, ContactName, ContactTitle, Address, City,
PostalCode, Phone, Fax
FROM Customers WHERE (CustomerID = @currCustomerID)

請注意,九個 SET 語句參數表示將寫入數據庫的當前值,而九個 WHERE 語句參數則表示用於定位初始記錄的初始值。

前九個 SET 語句參數對應於參數集合中的前九個參數。這些參數會將其 SourceVersion 屬性設置爲 Current。

接着的九個 WHERE 語句參數用於開放式併發。這些佔位符對應於參數集合中接着的九個參數,這些參數的每個都將其 SourceVersion 屬性設置爲 Original。

SELECT 語句用於在發生更新後刷新數據集。它是您在「高級 SQL 生成選項」對話框中設置「刷新數據集」選項時生成的。

注意 上面的 SQL 使用命名參數,而 OleDbDataAdapter 命令則使用問號 (?) 做爲參數佔位符。
默認狀況下,若是您在「數據適配器配置嚮導」中選擇「開放式併發」選項,Visual Studio 將爲您建立這些參數。此時將由您根據本身的業務要求來添加錯誤處理代碼。ADO.NET 提供了一個 DBConcurrencyException 對象,它返回違反併發規則的行。有關更多信息,請參見處理併發錯誤。

 

參考:http://www.cnblogs.com/badboy2008/articles/499283.html

相關文章
相關標籤/搜索