假設,我即將開始使用ASP.NET和SQL Server 2005的項目。我必須爲此應用程序設計併發需求。我打算在每個表格中添加一個TimeStamp列。在更新表格時,我將檢查TimeStamp列是否與選定的相同。Sql transactrion的併發處理
這種方法是否足夠?或者在任何情況下這種方法都有缺點嗎?
請指教。
感謝
Lijo
假設,我即將開始使用ASP.NET和SQL Server 2005的項目。我必須爲此應用程序設計併發需求。我打算在每個表格中添加一個TimeStamp列。在更新表格時,我將檢查TimeStamp列是否與選定的相同。Sql transactrion的併發處理
這種方法是否足夠?或者在任何情況下這種方法都有缺點嗎?
請指教。
感謝
Lijo
的首先,你在你的問題描述的方式在我看來與MS SQL ASP.NET應用程序的數據庫的最佳方式。數據庫中沒有鎖定。它與永久斷開連接的客戶端類似於Web客戶端是完美的。
如何從一些答案中讀到,在術語中存在誤解。我們都指使用Microsoft SQL Server 2008或更高版本來保存數據庫。如果您在MS SQL Server 2008文檔主題「rowversion(的Transact-SQL)」,在打開,你會發現以下幾點:
「時間戳對於 rowversion數據類型的同義詞,並受 數據類型同義詞的行爲。「...... 」的時間戳語法棄用。 此功能將在 未來版本的Microsoft SQL 服務器中刪除。避免在 新的開發工作中使用該功能,並計劃 修改當前使用 此功能的應用程序。」
所以時間戳數據類型爲MS SQL的rowversion數據類型的同義詞。它擁有64位,其在每個數據庫內部存在並且可以被看作是@@ DBTS。一個行的數據庫中的一個表的修改之後,計數器將被增加。
正如我讀取計數器你的問題我讀「時間戳」作爲類型rowversion數據的列名。我個人更喜歡名字RowUpdateTimeStamp。在AzManDB中(請參閱以數據庫爲商店的Microsoft授權管理器),我可以看到這樣的名稱。有時也用於ChildUpdateTimeStamp跟蹤分層RowUpdateTimeStamp結構(相對於觸發)。
我實現了這個辦法,我的最後一個項目,並很高興。一般來說,你做以下:
SELECT s.Id AS Id
,s.Name AS SoftwareName
,m.Name AS ManufacturerName
,CASE WHEN s.RowUpdateTimeStamp > m.RowUpdateTimeStamp
THEN s.RowUpdateTimeStamp
ELSE m.RowUpdateTimeStamp
END AS RowUpdateTimeStamp
FROM dbo.Software AS s
INNER JOIN dbo.Manufacturer AS m ON s.Manufacturer_Id=m.Id
或進行數據鑄像下面
SELECT s.Id AS Id
,s.Name AS SoftwareName
,m.Name AS ManufacturerName
,CASE WHEN s.RowUpdateTimeStamp > m.RowUpdateTimeStamp
THEN CAST(s.RowUpdateTimeStamp AS bigint)
ELSE CAST(m.RowUpdateTimeStamp AS bigint)
END AS RowUpdateTimeStamp
FROM dbo.Software AS s
INNER JOIN dbo.Manufacturer AS m ON s.Manufacturer_Id=m.Id
舉行RowUpdateTimeStamp爲BIGINT,其對應ULONG數據類型的C#。如果您從多個表中創建OUTER JOINT或JOINT,則所有表格中的構造MAX(RowUpdateTimeStamp)
將顯得稍微複雜一些。因爲MS SQL不支持像MAX(A,B,C,d,E)對應的構建函數可以看起來像以下:
(SELECT MAX(rv)
FROM (SELECT table1.RowUpdateTimeStamp AS rv
UNION ALL SELECT table2.RowUpdateTimeStamp
UNION ALL SELECT table3.RowUpdateTimeStamp
UNION ALL SELECT table4.RowUpdateTimeStamp
UNION ALL SELECT table5.RowUpdateTimeStamp) AS maxrv) AS RowUpdateTimeStamp
spSoftwareUpdate
存儲過程可能看起來像CREATE PROCEDURE dbo.spSoftwareUpdate
@Id int,
@SoftwareName varchar(100),
@originalRowUpdateTimeStamp bigint, -- used for optimistic concurrency mechanism
@NewRowUpdateTimeStamp bigint OUTPUT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
-- ExecuteNonQuery() returns -1, but it is not an error
-- one should test @NewRowUpdateTimeStamp for DBNull
SET NOCOUNT ON;
UPDATE dbo.Software
SET Name = @SoftwareName
WHERE Id = @Id AND RowUpdateTimeStamp <= @originalRowUpdateTimeStamp
SET @NewRowUpdateTimeStamp = (SELECT RowUpdateTimeStamp
FROM dbo.Software
WHERE (@@ROWCOUNT > 0) AND (Id = @Id));
END
dbo.spSoftwareDelete
存儲過程的代碼看起來像一樣。如果您未打開NOCOUNT
,則可以生成DBConcurrencyException在情景中會自動生成很多。 Visual Studio爲您提供了使用樂觀併發的可能性,如TableAdapter
或DataAdapter
的高級選項中的「使用樂觀併發」複選框。
如果你看看dbo.spSoftwareUpdate
存儲過程carful你會發現,我使用RowUpdateTimeStamp <= @originalRowUpdateTimeStamp
在WHERE而不是RowUpdateTimeStamp = @originalRowUpdateTimeStamp
。我這樣做是因爲,具有客戶端的@originalRowUpdateTimeStamp
的值通常是從多個表格構建爲MAX(RowUpdateTimeStamp)
。所以它可以是RowUpdateTimeStamp < @originalRowUpdateTimeStamp
。要麼你應該使用嚴格的相等性=並且在這裏重現與您在SELECT語句中使用的相同的複雜JOIN語句,或者使用< =像我這樣構建並保持與以前完全相同的安全性。
順便說一下,基於RowUpdateTimeStamp,可以爲數據創建非常好的價值ETag它可以在HTTP頭與數據一起發送到客戶端。通過使用ETag,您可以在客戶端實施智能數據緩存。
我不能在這裏寫完整的代碼,但你可以在互聯網上找到很多例子。我只想重申,在我看來,使用樂觀併發基於rowversion一次是在大多數的情況下ASP.NET的最佳途徑。
我不知道是應該併發在這樣的數據庫進行處理。數據庫本身應該能夠管理隔離和事務行爲,但是線程行爲應該在代碼中完成。
他沒有提到穿線。數據庫必須能夠處理併發訪問 - 無論這些來自單個多線程應用程序還是來自多個應用程序實例,或者兩者都不在此處,也不在此處。 – 2010-04-17 13:21:39
然後,他需要關注自己的酸性和孤立性。 – duffymo 2010-04-17 14:06:49
在SQL Server中,針對某種情況的推薦方法是創建一個類型爲'rowversion'的列,並使用它來檢查該行中是否有任何字段已更改。
SQL Server保證如果行中的任何值發生更改(或插入新行),則rowversion列會自動更新爲不同的值。讓數據庫爲你處理這個比你自己做的更可靠。
在您的更新語句中,您只需添加一個where子句來檢查rowversion值是否與您第一次檢索該行時的值相同。如果不是這樣,別人已經改變了行(即:它的骯髒)
而且,從該頁面:
時間戳語法已被棄用。 此功能將在 未來版本的Microsoft SQL 服務器中刪除。避免在 新開發工作中使用此功能,並計劃到 修改當前使用 此功能的應用程序。
排版建議是正確的我會說,但它令人失望地看到時間戳將很快被棄用。我的一些舊應用程序因爲不同的原因而使用它,然後檢查併發性。
可能不是一個好主意 - 看看這篇文章http://www.mssqltips.com/tip.asp?tip=1501 – 2010-04-17 13:12:13
謝謝。它提供了一些亮點。一個問題 - 爲什麼我們說在悲觀條件下使用鎖定比時間戳更好?假設user1讀取它並去了他的辦公室,其他用戶在得到錯誤信息之前必須等很長時間,對吧?如果我們使用時間戳方法,我們不能得到即時回覆? 這裏缺少的鏈接是什麼? – Lijo 2010-04-17 13:38:44
「悲觀條件」意味着鎖定 - 這就是爲什麼很多人知道他們在做什麼使用它 – 2010-04-17 13:43:29