正在更新语句中获取最新的行版本/时间戳值-Sql Server



我使用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()的函数可以用于标识列,但找不到这样的函数。有人知道我是否遗漏了什么吗?

提前谢谢。

来自MSDN:

@@DBTS返回当前数据库最后使用的时间戳值。当具有时间戳列的行插入或更新。

您的问题是,在更新和选择之间,其他人会更新行。因此,当您在更新语句后进行选择时,不会得到相同的值。这是一个不可重复读取的问题。您应该在update语句中使用锁定提示(UPDLLOCK)。此锁将允许读卡器(即共享锁),但会阻止写入程序。所以更新后您将得到相同的行。所以你的存储过程应该是-

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

最新更新