You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

回滚事务中DBCC CHECKIDENT(RESEED)的异常行为合理性咨询

这确实是SQL Server的正确行为,原因和IDENTITY列的核心设计逻辑直接相关

先复现你的测试代码方便参考:

DROP TABLE IF EXISTS __Test; CREATE TABLE __Test (Id INT IDENTITY NOT NULL PRIMARY KEY); 
GO 
BEGIN TRAN; 
SET IDENTITY_INSERT __Test ON; 
INSERT INTO __Test (Id) VALUES (100); 
SET IDENTITY_INSERT __Test OFF; 
DBCC CHECKIDENT('__Test', RESEED, 1); 
ROLLBACK TRAN; 
GO 
SELECT IDENT_CURRENT('__Test'); -- returns 100 instead of 1

你的预期和实际结果的差异,本质是IDENTITY列的标识值(由IDENT_CURRENT返回)在两种操作下的事务行为完全不同:

1. IDENTITY_INSERT插入触发的标识值更新是不可回滚的

当你通过IDENTITY_INSERT插入自定义标识值时,SQL Server会自动将当前标识值更新为你插入的最大值——这是为了保证后续自动生成的标识值不会和已存在的值重复。关键在于:这个标识值的更新是直接写入系统元数据的,完全不受事务回滚影响。哪怕你回滚了插入的行,系统也不会把标识值退回去,因为如果允许回滚,可能会导致其他并发事务生成重复的标识值,直接违反IDENTITY列的唯一性设计目标。

在你的测试里,插入ID=100后,IDENT_CURRENT就已经被设置为100,这个修改已经“生效”,和事务是否提交无关。

2. DBCC CHECKIDENT的RESEED操作是可以被事务回滚的

DBCC CHECKIDENT('__Test', RESEED, 1)属于显式修改标识值的元数据操作,这类操作在SQL Server中支持事务回滚。当你在事务内执行这个RESEED时,标识值暂时被改为1,但一旦事务回滚,这个修改就会被撤销,系统会恢复到RESEED之前的标识值——也就是之前IDENTITY_INSERT插入时设置的100。

这就是为什么你最终查询IDENT_CURRENT('__Test')会返回100而非预期的1:回滚只撤销了RESEED的修改,却无法撤销IDENTITY_INSERT带来的标识值更新。

总结来说:IDENTITY列的标识值设计优先保证唯一性,而非事务一致性。IDENTITY_INSERT触发的标识值更新是持久化的元数据修改,不受事务回滚影响;而显式的RESEED操作属于可回滚的元数据修改,事务回滚后会恢复到操作前的状态。

内容的提问来源于stack exchange,提问作者Palo Mraz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 21:49:05