6

我正在使用 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() 的函数用于标识列,但找不到类似的东西。有人知道我是否遗漏了什么吗?

提前致谢。

4

2 回答 2

1

来自MSDN

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

于 2013-10-23T15:04:00.557 回答
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
于 2016-01-27T18:45:25.760 回答