我使用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