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介绍

相关推荐
man20171 小时前
【2024最新】基于springboot+vue的闲一品交易平台lw+ppt
vue.js·spring boot·后端
hlsd#1 小时前
关于 SpringBoot 时间处理的总结
java·spring boot·后端
路在脚下@1 小时前
Spring Boot 的核心原理和工作机制
java·spring boot·后端
幸运小圣2 小时前
Vue3 -- 项目配置之stylelint【企业级项目配置保姆级教程3】
开发语言·后端·rust
前端SkyRain3 小时前
后端Node学习项目-用户管理-增删改查
后端·学习·node.js
提笔惊蚂蚁3 小时前
结构化(经典)软件开发方法: 需求分析阶段+设计阶段
后端·学习·需求分析
老猿讲编程3 小时前
Rust编写的贪吃蛇小游戏源代码解读
开发语言·后端·rust
黄小耶@3 小时前
python如何使用Rabbitmq
分布式·后端·python·rabbitmq
宅小海5 小时前
Scala-List列表
开发语言·后端·scala
蔚一5 小时前
Javaweb—Ajax与jQuery请求
前端·javascript·后端·ajax·jquery