获取更新语句中的最新rowversion / timestamp值 - Sql Server

时间:2012-07-06 08:58:14

标签: sql-server tsql concurrency optimistic-concurrency

我正在使用rowversion列来处理乐观并发,并希望在我完成更新时获取新的rowversion值,以便我的数据层具有最新值,并且可以通过获取并发异常执行另一个更新(除非该记录已由其他人更新。

我在更新后只是在数据层中进行了操作,但这不是非常有效或完全可靠。

对于下表:

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文档中的OUTPUT语句(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()的函数来识别标识列,但找不到类似的东西。任何人都知道我是否遗漏了什么?

提前致谢。

2 个答案:

答案 0 :(得分:1)

来自MSDN

  

@@ DBTS返回当前数据库的上次使用的时间戳值。   当具有时间戳列的行时,将生成新的时间戳值   插入或更新。

答案 1 :(得分:0)

您的问题是在更新和选择其他人之间更新行。因此,当您在更新语句后选择时,您将得不到相同的值。这是一个不可重复读取的问题。您应该使用带有update语句的锁定提示(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