SqlServer timestamp类型

前言:

最近在对接客户数据的时候发现有SqlServer数据库里面有timestamp类型,一开始以为跟mysql,postgresql的timestamp类型差不多,是时间类型。结果接入之后发现竟然是二进制的,就感觉到很困惑,为什么时间类型要用二进制来存呢?难道是有什么优势可言吗?查了资料之后发现,原来SqlServer比较早期的版本里面timestamp是一个递增的数字,用来记录行增加和更新的次数,而不是用来记录时间的字段,所以这个类型的字段是没有业务含义的字段,数据接入的时候忽略这个字段或者直接置为null就可以了。另外提一嘴,我原本以为SqlServer只会出现在大学教学数据库的时候存在,结果发现它还是有很多的用户在使用的,微软的生态还是挺强大的。

介绍:

概念

timestamp在sqlServer早期版本比如SqlServer2008,还是叫做timestamp,后面新一些的版本就叫rowversion了,这个也更贴切它的作用,所以timestamp和rowversion是同一个东西,SqlServer的timestamp和ISO标准的timestamp数据类型是不一样的,这个要注意。官网的描述是,每个数据库都有一个计数器,当对数据库中包含 rowversion 列的表执行插入或更新操作时,该计数器值就会增加。 此计数器是数据库行版本。 这可以跟踪数据库内的相对时间,而不是时钟相关联的实际时间。 一个表只能有一个 rowversion 列。 每次修改或插入包含 rowversion 列的行时,就会在 rowversion 列中插入经过增量的数据库 rowversion 值。 这一属性使 rowversion 列不适合作为键使用,尤其是不能作为主键使用,因为它是一直变化的。

具体使用:

官网对timestamp的使用并没有很多着笔,可能是因为一般用户使用不到这个字段类型的。

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

sql 复制代码
CREATE TABLE ExampleTable (PriKey int PRIMARY KEY, timestamp);  

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

sql 复制代码
CREATE TABLE ExampleTable2 (PriKey int PRIMARY KEY, VerCol rowversion) ;  

稍微要一点的是,不可为空的 rowversion 列在语义上等同于 binary(8) 列, 可为空的 rowversion 列在语义上等同于varbinary(8) 列。

可以使用某行的 rowversion 列轻松确定自上次读取该行后,是否对该行运行过更新语句。 如果对该行运行过更新语句,则会更新 rowversion 值。 如果没有对该行运行过更新语句,则 rowversion 值将与以前读取该行时的 rowversion 值相同。 若要返回数据库的当前行版本值,请使用 @@DBTS

因为每次数据更新timestamp都会变化,所以可以利用这个特性来作为乐观锁。

这个是官网给的例子,<myRv> 来表示上次读取该行时的 rowversion 值:

sql 复制代码
DECLARE @t TABLE (myKey int);  
UPDATE MyTest  
SET myValue = 2  
    OUTPUT inserted.myKey INTO @t(myKey)   
WHERE myKey = 1   
    AND RV = <myRv>;  
IF (SELECT COUNT(*) FROM @t) = 0  
    BEGIN  
        RAISERROR ('error changing row with myKey = %d'  
            ,16 -- Severity.  
            ,1 -- State   
            ,1) -- myKey that was changed   
    END;  

我们在写代码的时候也是一样,先读取到timestamp的值t1,然后更新的时候在where条件里面比较一下当前的timestamp值和上次t1是不是一样的。如果不一样,说明这行数据已经被其他线程修改过了,要重头再来一次更新的操作。如果一样的话,就证明这个数据只有我们修过过了,这就是数据库乐观锁的使用。

注意事项:

1.timestamp/rowverion是同一个东西,是记录数据行插入/更新的计数器,和ISO标准的timestamp不一样

2.如果要使用日期或者时间,最好使用datetime2

下面是SqlServer2016-2022的时间类型的表格,可以根据情况使用。

数据类型 格式 范围 精确度 存储大小(字节) 用户定义的秒的小数部分精度 时区偏移量
time hh:mm:ss[.nnnnnnn] 00:00:00.0000000 到 23:59:59.9999999 100 纳秒 3 到 5
date YYYY-MM-DD 0001-01-01 到 31.12.99 1 天 3
smalldatetime YYYY-MM-DD hh:mm:ss 1900-01-01 到 2079-06-06 1 分钟 4
datetime YYYY-MM-DD hh:mm:ss[.nnn] 1753-01-01 到 9999-12-31 0.00333 秒 8
datetime2 YYYY-MM-DD hh:mm:ss[.nnnnnnn] 0001-01-01 00:00:00.0000000 到 9999-12-31 23:59:59.9999999 100 纳秒 6 到 8
datetimeoffset YYYY-MM-DD hh:mm:ss[.nnnnnnn] [+|-]hh:mm 0001-01-01 00:00:00.0000000 到 9999-12-31 23:59:59.9999999(以 UTC 时间表示) 100 纳秒 8 到 10

3.一张表只能有一个timestamp列,在往这张表上增加timestamp列就会报错

实际测试也是如此,在测试的表上在加一列timestamp就会报错,提示已经有timestamp列了:

参考资料:

1.sql时间类型介绍

2.rowversion类型

3.timetamp介绍

相关推荐
SomeB1oody1 分钟前
【Rust自学】7.4. use关键字 Pt.2 :重导入与换国内镜像源教程
开发语言·后端·rust
新知图书6 分钟前
Rust编程与项目实战-箱
开发语言·后端·rust
SomeB1oody10 分钟前
【Rust自学】7.3. use关键字 Pt.1:use的使用与as关键字
开发语言·后端·rust
minstbe20 分钟前
WEB开发 - Flask 入门:Jinja2 模板语法进阶 Python
后端·python·flask
无名之逆1 小时前
lombok-macros
开发语言·windows·后端·算法·面试·rust·大学期末
m0_748247801 小时前
SpringBoot集成Flowable
java·spring boot·后端
散一世繁华,颠半世琉璃1 小时前
SpringBoot揭秘:URL与HTTP方法如何定位到Controller
spring boot·后端·http
安晴晚风2 小时前
从0开始在linux服务器上部署SpringBoot和Vue
linux·运维·前端·数据库·后端·运维开发
海绵波波1078 小时前
flask后端开发(10):问答平台项目结构搭建
后端·python·flask
网络风云10 小时前
【魅力golang】之-反射
开发语言·后端·golang