rowversion (Transact-SQL)

公开数据库中自动生成的唯一二进制数字的数据类型。rowversion 通常用作给表行加版本戳的机制。存储大小为 8 个字节。rowversion 数据类型只是递增的数字,不保留日期或时间。若要记录日期或时间,请使用 datetime2 数据类型。

注释

每个数据库都有一个计数器,当对数据库中包含 rowversion 列的表执行插入或更新操作时,该计数器值就会增加。此计数器是数据库行版本。这可以跟踪数据库内的相对时间,而不是时钟相关联的实际时间。一个表只能有一个 rowversion 列。每次修改或插入包含 rowversion 列的行时,就会在 rowversion 列中插入经过增量的数据库行版本值。这一属性使 rowversion 列不适合作为键使用,尤其是不能作为主键使用。对行的任何更新都会更改行版本值,从而更改键值。如果该列属于主键,那么旧的键值将无效,进而引用该旧值的外键也将不再有效。如果该表在动态游标中引用,则所有更新均会更改游标中行的位置。如果该列属于索引键,则对数据行的所有更新还将导致索引更新。

timestamp 的数据类型为 rowversion 数据类型的同义词,并具有数据类型同义词的行为。在 DDL 语句,请尽量使用 rowversion 而不是 timestamp。有关详细信息,请参阅数据类型同义词 (Transact-SQL)

Transact-SQL timestamp 数据类型不同于在 ISO 标准中定义的 timestamp 数据类型。

注意注意

不推荐使用 timestamp 语法。后续版本的 Microsoft SQL Server 将删除该功能。请避免在新的开发工作中使用该功能,并着手修改当前还在使用该功能的应用程序。

在 CREATE TABLE 或 ALTER TABLE 语句中,不必为 timestamp 数据类型指定列名,例如:

CREATE TABLE ExampleTable (PriKey int PRIMARY KEY, timestamp);

如果不指定列名,则 SQL Server 数据库引擎 将生成 timestamp 列名;但 rowversion 同义词不具有这样的行为。在使用 rowversion 时,必须指定列名,例如:

CREATE TABLE ExampleTable2 (PriKey int PRIMARY KEY, VerCol rowversion) ;
注意注意

通过使用在其 SELECT 列表中包含了 rowversion 列的 SELECT INTO 语句,可以生成重复的 rowversion 值。建议不要以这种方式使用 rowversion。

不可为空的 rowversion 列在语义上等同于 binary(8) 列。可为空的 rowversion 列在语义上等同于 varbinary(8) 列。

使用某一行中的 rowversion 列可以很容易地确定该行中的任何值自上次读取以后是否发生了更改。如果对该行进行了任何更改,就会更新行版本的值。如果没有对行进行更改,则行版本值将与以前读取该行时的行版本值相同。若要返回数据库的当前行版本值,请使用 @@DBTS

当多个用户正在同时更新行时,可以在表中添加一个 rowversion 列以帮助维护数据库的完整性。此外,您可能还想要在不重新查询表的情况下了解有多少行被更新以及哪些行被更新。

例如,假定您创建了一个名为 MyTest 的表。您通过运行下面的 Transact-SQL 语句在表中填充一些数据。

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

然后,可以使用以下示例 Transact-SQL 语句在更新期间实现 MyTest 表的乐观并发控制。

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 是该行的 rowversion 列值,指示上一次读取行的时间。必须使用实际的 rowversion 值替换此值。实际的 rowversion 值可以是类似 0x00000000000007D3 这样的值。

还可以将示例 Transact-SQL 语句放在事务中。通过在事务的作用域中查询 @t 变量,可以在不重新查询 MyTest 表的情况下检索表的更新后的 myKey 列。

以下是使用 timestamp 语法的同一个示例:

CREATE TABLE MyTest2 (myKey int PRIMARY KEY
    ,myValue int, TS timestamp);
GO 
INSERT INTO MyTest2 (myKey, myValue) VALUES (1, 0);
GO 
INSERT INTO MyTest2 (myKey, myValue) VALUES (2, 0);
GO
DECLARE @t TABLE (myKey int);
UPDATE MyTest2
SET myValue = 2
    OUTPUT inserted.myKey INTO @t(myKey) 
WHERE myKey = 1 
    AND TS = 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;