如果语句在事务块内失败,是否可以重新创建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
3号身份因ROLLBACK TRANSACTION
而丢失。可以恢复吗?
答案 0 :(得分: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;
文档的Remarks部分专门声明,不保证连续的值:
Identity列可用于生成键值。身份 列上的属性可确保满足以下条件:
...
交易中的连续值 –插入交易 多行不能保证获得行的连续值 因为其他并发插入可能会在表上发生。如果值 必须是连续的,则交易应使用排他锁 或使用SERIALIZABLE隔离级别。
服务器重启或其他故障后的连续值 – SQL Server 出于性能原因可能会缓存身份值,并且某些 数据库故障或服务器期间分配的值可能会丢失 重新开始。这可能导致插入时身份值出现空白。如果 差距是不可接受的,那么应用程序应该使用自己的 生成键值的机制。将序列发生器与 NOCACHE选项可以限制与从未交易的差距 承诺。
重复使用值 –对于具有特定标识的给定标识属性 种子/增量,标识值不会被引擎重用。如果一个 特定的插入语句失败或插入语句已滚动 然后,消耗的身份值将丢失,并且不会 再次产生。这可能会导致在后续标识时出现空白 值生成。