【问题标题】:Weird behavior of DBCC CHECKIDENT with RESEED in a rolled-back transaction回滚事务中带有 RESEED 的 DBCC CHECKIDENT 的奇怪行为
【发布时间】:2021-07-09 12:28:25
【问题描述】:

考虑以下 T-SQL 代码(该代码与 ADO.NET 版本一起在此 GitHub 存储库 https://github.com/PaloMraz/SqlServerReseedSampleApp 中提供):

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 列的 __Test 表。
  • 启动事务。
    • 插入新行,将 IDENTITY 种子值覆盖为 100。
    • 将 IDENTITY 重新设置为 1。
    • 回滚事务。
  • 查询当前身份。

我已经预料到,当前的身份值会回到 1,但实际上是 100。这意味着事务回滚了插入的行和 DBCC CHECKIDENT 命令的结果,但没有回滚覆盖的 IDENTITY 种子!

这是正确的行为吗?为什么?

感谢您的宝贵时间!

【问题讨论】:

  • 更奇怪的是,如果有另一个插入 after CHECKIDENT,回滚会将你带到 before CHECKIDENT 的值。我本来预计两者都不会回滚,因为 IDENTITY 值不应该参与事务

标签: sql-server tsql dbcc


【解决方案1】:

这里唯一真正的问题是为什么 DBCC CHECKIDENT ... RESEED 可以回滚。使用 IDENTITY INSERT 或不插入具有 IDENTITY 列的表将增加当前身份值,而不会阻止其他会话生成新 IDENTITY 值的能力。为此,当前 IDENTITY 值的修改不得纳入会话事务中。

DBCC CHECKIDENT 实际上是一个 DDL 语句,就像 ALTER TABLE。它需要对象上的独占元数据锁,因此可以提交或回滚。 EG

BEGIN TRAN;
DBCC CHECKIDENT('__Test', RESEED, 100);

select *
from sys.dm_tran_locks
where request_session_id = @@spid 

ROLLBACK TRAN;

将在目标表上显示 Sch-M 锁。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-21
    • 2023-03-31
    • 1970-01-01
    • 2015-07-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多