重新生成丢失的身份值

Har*_*a W 2 sql sql-server auto-increment

如果事务块中的语句失败,有没有办法重新创建SQL Server表的标识值?

请仔细阅读以下代码:

DECLARE @IdentityTable AS TABLE (ID INT IDENTITY(1, 1), Description VARCHAR(50))

INSERT INTO @IdentityTable (Description) 
VALUES('Test1')

BEGIN TRY 
BEGIN TRANSACTION IdentityTest
    INSERT INTO @IdentityTable (Description) 
    VALUES('Test2')

    INSERT INTO @IdentityTable (Description) 
    VALUES(1/0)

    COMMIT TRANSACTION IdentityTest
END TRY
BEGIN CATCH
    ROLLBACK TRANSACTION IdentityTest
END CATCH

INSERT INTO @IdentityTable (Description) 
VALUES('Test4')

SELECT * FROM @IdentityTable
Run Code Online (Sandbox Code Playgroud)

结果

身份3号丢失归因于ROLLBACK TRANSACTION.有可能重新获得它吗?

Lar*_*rnu 5

您正在尝试使用该IDENTITY属性生成连续数字并进行维护; 这不是IDENTITY为了什么.它旨在提供基于当前种子的递增值(在它自己的基础上(没有PRIMARY KEY约束或UNIQUE INDEX),它甚至不保证唯一性,因为种子可以更改(感谢HoneyBadger提醒我这么早)).

如果INSERT失败,则值的值IDENTITY仍将增加.此外,如果你DELETE从一个表中排成一行,那么不会导致每个"后一行"的ID都相应地更新; 因此你也会有一个差距.

确保你得到一个递增的价值的唯一保证的方法是使用一个功能类似ROW_NUMBER运行时间.例如:

SELECT ROW_NUMBER() OVER (ORDER BY ID) AS cID,
       Description
FROM YourTable;
Run Code Online (Sandbox Code Playgroud)

文档的备注部分明确指出连续值不是保证的:

标识列可用于生成键值.列上的标识属性保证以下内容:

...

事务中的连续值 - 插入多行的事务不能保证获得行的连续值,因为表上可能会出现其他并发插入.如果值必须是连续的,则事务应使用表上的独占锁或使用SERIALIZABLE隔离级别.

服务器重新启动或其他故障后的连续值 - 由于性能原因,SQL Server可能会缓存标识值,并且在数据库故障或服务器重新启动期间,某些分配的值可能会丢失.这可能导致插入时身份值的缺口.如果差距不可接受,那么应用程序应使用自己的机制来生成密钥值.使用带有NOCACHE选项的序列生成器可以限制从未提交的事务的间隙.

重用值 - 对于具有特定种子/增量的给定标识属性,引擎不会重用标识值.如果特定的insert语句失败或者回滚insert语句,则消耗的标识值将丢失,并且不会再次生成.当生成后续标识值时,这可能导致间隙.