2012-07-06 88 views
5

我使用rowversion列來處理樂觀併發,並希望在更新完成後獲取新的rowversion值,以便我的數據層具有最新值並可以通過獲取併發異常來執行另一次更新(除非該記錄已被其他人更新)。在更新語句中獲取最新的rowversion/timestamp值 - SQL Server

我只是在做了一個更新後進入數據層,但這並不是非常有效或者完全可靠。

爲下表:

CREATE TABLE PurchaseType 
(
    PurchaseTypeCode nvarchar(20) NOT NULL PRIMARY KEY CLUSTERED (PurchaseTypeCode), 
    Name nvarchar(50) NOT NULL, 
    TS rowversion NOT NULL 
) 

我想:

CREATE PROCEDURE PurchaseType_UpdateWithGet 
@PurchaseTypeCode nvarchar(20), 
@Name nvarchar(50), 
@TS rowversion OUTPUT  
AS 

UPDATE PurchaseType 
SET Name = @Name 
WHERE PurchaseTypeCode = @PurchaseTypeCode 
AND TS = @TS 

SELECT @TS = TS FROM PurchaseType WHERE PurchaseTypeCode = @PurchaseTypeCode 
GO 

但因爲沒有得到來自別人的更新rowverion值的可能性不是完全滿意。然後,我在rowversion文檔(http://msdn.microsoft.com/en-us/library/ms182776.aspx/http://msdn.microsoft.com/en-us/library/ms177564.aspx)在輸出語句來了,嘗試這樣:

CREATE PROCEDURE PurchaseType_UpdateWithOutput 
@PurchaseTypeCode nvarchar(20), 
@Name nvarchar(50), 
@TS rowversion OUTPUT  
AS 

DECLARE @Output TABLE (TS BINARY(8)) 

UPDATE PurchaseType 
SET Name = @Name 
    OUTPUT inserted.TS into @Output 
WHERE PurchaseTypeCode = @PurchaseTypeCode 
    AND TS = @TS 

SELECT TOP 1 @TS = TS FROM @Output 
GO 

這種運作良好。在我非常基本的測試中(只需運行10000個調用並對其進行計時),OUTPUT選項需要大約40%的時間,但仍不到半毫秒。 SET STATISTICS TIME ON也沒有任何可測量的時間。

我的問題是,有沒有人知道更好/更簡單的方法來做到這一點?

我曾希望我可以使用類似於SCOPE_IDENTITY()作爲標識列的函數,但找不到類似的東西。任何人都知道我錯過了什麼?

在此先感謝。

+0

輸出是去檢索插入任何產生價值的方式(這包括如果你問我IDENTITY ...) – 2012-07-06 09:34:22

+0

OK,感謝。爲什麼你喜歡通過SCOPE_IDENTITY輸出的任何特定原因? – 2012-07-06 13:49:38

+2

它適用於多行插入 – 2012-07-06 18:39:28

回答

0

MSDN

@@ DBTS返回當前數據庫的上次使用時間戳值。 插入或更新帶有時間戳記列 的行時會生成新的時間戳記值。

+2

謝謝,我不知道這件事。除非我錯了。它在這種情況下不能可靠地工作,因爲它是數據庫範圍(與@@ identity相似),而不是作用域(與SCOPE_IDENTITY()類似)。 – 2013-11-14 16:37:18

+0

你說得對,那是一個缺點。我猜OUTPUT是剩下的唯一方法。 – 2013-11-14 17:01:37

0

你的問題是在更新和選擇別人更新行。所以當你在更新語句後選擇時,你不會得到相同的值。這是一個不可重複讀取的問題。您應該使用更新語句的鎖定提示(UPDLOCK)。這個鎖將允許讀者(即共享鎖),但會阻止作者。所以你會在更新後得到相同的行。所以,你的存儲過程應該是 -

CREATE PROCEDURE PurchaseType_UpdateWithGet 
@PurchaseTypeCode nvarchar(20), 
@Name nvarchar(50), 
@TS rowversion OUTPUT  
AS 

UPDATE PurchaseType with (updlock) 
SET Name = @Name 
WHERE PurchaseTypeCode = @PurchaseTypeCode 
AND TS = @TS 

SELECT @TS = TS FROM PurchaseType WHERE PurchaseTypeCode = @PurchaseTypeCode 
GO