我正在使用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()的函数来识别标识列,但找不到类似的东西。任何人都知道我是否遗漏了什么?
提前致谢。
答案 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