需要帮助理解这个关于 SQL 服务器 rowversion 的例子吗?
Need help understand this example about SQL Server rowversion?
在阅读这个例子之前,我自己可以理解rowversion,它反映了记录上最后更新的时间戳。我想它的用法是这样的:首先读取一条记录后,应该得到rowversion列的值。然后在更新该记录之前,应检查本地存储的 rowversion 值与从数据库中获取的当前 rowversion 值(在更新之前的时间),如果它们不相等则意味着已经有来自另一个用户和当前应用程序的一些更新应该用自己的策略处理这种并发情况。
但是我认为以下 example 要么使问题过于复杂,要么甚至可能是错误的或解释不当(因此导致混淆):
CREATE TABLE MyTest (myKey int PRIMARY KEY
,myValue int, RV rowversion);
GO
INSERT INTO MyTest (myKey, myValue) VALUES (1, 0);
GO
INSERT INTO MyTest (myKey, myValue) VALUES (2, 0);
GO
DECLARE @t TABLE (myKey int);
UPDATE MyTest
SET myValue = 2 OUTPUT inserted.myKey INTO @t(myKey)
WHERE myKey = 1 AND RV = myValue;
IF (SELECT COUNT(*) FROM @t) = 0
BEGIN
RAISERROR ('error changing row with myKey = %d'
,16 -- Severity.
,1 -- State
,1) -- myKey that was changed
END;
我注意到 myValue
在这里,它设置为 2
并且还用于 WHERE 子句中以检查 RV
列。据我了解,rowversion 列显然是 RV
但它解释了这一点:
myValue is the rowversion column value for the row that indicates the last time that you read the row. This value must be replaced by the actual rowversion value
这里我觉得myValue
和rowversion没有关系,应该只是作为用户数据。那么有了这样的解释,MyTest
table 有 2 个 rowversion 列?而 myValue
显然声明为 int
?
我能想到的一种可能性是 myValue
在 WHERE 条件下的理解不同(意味着它不是 SET 子句中的 myValue
),它可能只是一个占位符,例如在之前读取记录时读取 RV
的值。只有这种可能性对我有意义。
据我了解,示例应该是这样的:
SET myValue = 2 OUTPUT inserted.myKey INTO @t(myKey)
WHERE myKey = 1 AND RV = rowVersionValueFromTheLastTimeReading
我以前听说过 timestamp
,但 rowversion
对我来说还很陌生,当我试图找到更多相关信息时,我发现这个例子让我很困惑。你对此有何看法?或者我根本不明白rowversion的一些神秘用法?谢谢。
时间戳是行版本的数据库同义词。你不需要了解任何奥秘,你不应该使用它。它已被弃用,将来会被删除。
联机丛书中的示例不正确。我看到在该主题的社区评论中提到了这一点。
下面的代码显示了如何使用 rowversion
来实现开放式并发。当数据呈现给用户进行更新然后修改时,通常会采用这种方法。
DECLARE
@MyKey int = 1
,@NewMyValue int = 1
,@OriginalMyValue int
,@OriginalRV rowversion
--get original data, including rowversion
SELECT
@OriginalMyValue = myValue
, @OriginalRV = RV
FROM dbo.MyTest
WHERE myKey = 1;
--check original rowversion value when updating row
UPDATE dbo.MyTest
SET myValue = @NewMyValue
WHERE
myKey = 1
AND RV = @OriginalRV;
--optimistic concurrency violation
IF @@ROWCOUNT = 0
RAISEERROR ('Data was updated or deleted by another user.', 16, 1);
或者,可以检查原始数据值而不是 rowversion
。但是,如果您有很多列并且需要检查 NULL
值,这会变得很笨拙。这就是 rowversion
派上用场的地方。
--check original rowversion value when updating row
UPDATE dbo.MyTest
SET myValue = @NewMyValue
WHERE
myKey = 1
AND (myValue = @OriginalMyValue
OR (myValue IS NULL AND @OriginalMyValue IS NULL));
在阅读这个例子之前,我自己可以理解rowversion,它反映了记录上最后更新的时间戳。我想它的用法是这样的:首先读取一条记录后,应该得到rowversion列的值。然后在更新该记录之前,应检查本地存储的 rowversion 值与从数据库中获取的当前 rowversion 值(在更新之前的时间),如果它们不相等则意味着已经有来自另一个用户和当前应用程序的一些更新应该用自己的策略处理这种并发情况。
但是我认为以下 example 要么使问题过于复杂,要么甚至可能是错误的或解释不当(因此导致混淆):
CREATE TABLE MyTest (myKey int PRIMARY KEY
,myValue int, RV rowversion);
GO
INSERT INTO MyTest (myKey, myValue) VALUES (1, 0);
GO
INSERT INTO MyTest (myKey, myValue) VALUES (2, 0);
GO
DECLARE @t TABLE (myKey int);
UPDATE MyTest
SET myValue = 2 OUTPUT inserted.myKey INTO @t(myKey)
WHERE myKey = 1 AND RV = myValue;
IF (SELECT COUNT(*) FROM @t) = 0
BEGIN
RAISERROR ('error changing row with myKey = %d'
,16 -- Severity.
,1 -- State
,1) -- myKey that was changed
END;
我注意到 myValue
在这里,它设置为 2
并且还用于 WHERE 子句中以检查 RV
列。据我了解,rowversion 列显然是 RV
但它解释了这一点:
myValue is the rowversion column value for the row that indicates the last time that you read the row. This value must be replaced by the actual rowversion value
这里我觉得myValue
和rowversion没有关系,应该只是作为用户数据。那么有了这样的解释,MyTest
table 有 2 个 rowversion 列?而 myValue
显然声明为 int
?
我能想到的一种可能性是 myValue
在 WHERE 条件下的理解不同(意味着它不是 SET 子句中的 myValue
),它可能只是一个占位符,例如在之前读取记录时读取 RV
的值。只有这种可能性对我有意义。
据我了解,示例应该是这样的:
SET myValue = 2 OUTPUT inserted.myKey INTO @t(myKey)
WHERE myKey = 1 AND RV = rowVersionValueFromTheLastTimeReading
我以前听说过 timestamp
,但 rowversion
对我来说还很陌生,当我试图找到更多相关信息时,我发现这个例子让我很困惑。你对此有何看法?或者我根本不明白rowversion的一些神秘用法?谢谢。
时间戳是行版本的数据库同义词。你不需要了解任何奥秘,你不应该使用它。它已被弃用,将来会被删除。
联机丛书中的示例不正确。我看到在该主题的社区评论中提到了这一点。
下面的代码显示了如何使用 rowversion
来实现开放式并发。当数据呈现给用户进行更新然后修改时,通常会采用这种方法。
DECLARE
@MyKey int = 1
,@NewMyValue int = 1
,@OriginalMyValue int
,@OriginalRV rowversion
--get original data, including rowversion
SELECT
@OriginalMyValue = myValue
, @OriginalRV = RV
FROM dbo.MyTest
WHERE myKey = 1;
--check original rowversion value when updating row
UPDATE dbo.MyTest
SET myValue = @NewMyValue
WHERE
myKey = 1
AND RV = @OriginalRV;
--optimistic concurrency violation
IF @@ROWCOUNT = 0
RAISEERROR ('Data was updated or deleted by another user.', 16, 1);
或者,可以检查原始数据值而不是 rowversion
。但是,如果您有很多列并且需要检查 NULL
值,这会变得很笨拙。这就是 rowversion
派上用场的地方。
--check original rowversion value when updating row
UPDATE dbo.MyTest
SET myValue = @NewMyValue
WHERE
myKey = 1
AND (myValue = @OriginalMyValue
OR (myValue IS NULL AND @OriginalMyValue IS NULL));