即使使用事务回滚,SQL标识(自动编号)也会增加

muh*_*han 76 .net sql transactions sql-server-2005 identity-column

我有一个.net事务与SQL插入到SQL Server 2005数据库.该表具有标识主键.

当事务中发生错误时,将Rollback()被调用.行插入正确回滚,但是下次将数据插入表时,标识会增加,就好像回滚从未发生过一样.所以基本上在身份序列中存在差距.有没有办法让Rollback()方法回收丢失的身份?

我没有以正确的方式接近这个吗?

Jas*_*son 101

如果你考虑一下,自动增量号码不应该是事务性的.如果其他交易必须等待查看自动号码是否将被使用或"回滚",则使用自动号码的现有交易将阻止它们.例如,使用表A的自动编号字段考虑下面的psuedo代码与表A:

User 1
------------
begin transaction
insert into A ...
insert into B ...
update C ...
insert into D ...
commit


User 2
-----------
begin transaction
insert into A ...
insert into B ...
commit
Run Code Online (Sandbox Code Playgroud)

如果用户2的事务在用户1之后的一毫秒开始,那么他们插入表A将不得不等待用户1的整个事务完成,以查看是否使用了从第一次插入到A的自动编号.

这是一个功能,而不是一个bug.如果您需要紧密顺序,我建议使用另一种方案来生成自动编号.


Mar*_*ett 32

如果你依赖于你的身份价值无间隙,那么是 - 你做错了.一个整点代理键来是有没有商业意义.

并且,不,没有办法改变这种行为(没有滚动你自己的自动增量,并且遭受阻止其他插入的性能影响).


Bil*_*win 16

如果你DELETE排成一行,你的序列也会有差距.

序列必须是唯一的,但它们不需要是顺序的.它们单调增加的事实只是一个实施的侥幸.


Gav*_*ler 6

据我所知,插入的行声称自动编号并且在回滚时该编号丢失了.如果您依赖于正在排序的自动编号,您可能需要考虑您正在使用的方法.


Ian*_*ley 6

所有其他说不要担心的海报,以及你应该得到差距的海报,都是正确的.如果对数字有商业意义,并且该含义不存在差距,则不要使用标识列.

仅供参考,如果由于某种原因您想要消除差距,大多数数据库都可以将自动编号重新设置为您选择的编号.这是一个痛苦的屁股,如果你发现自己需要定期做,你绝对不应该使用自动编号/身份字段,如上所述.但这是在SQL服务器中执行此操作的代码:

DBCC CHECKIDENT('产品',RESEED,0)

这将产品表设置为从1开始(尽管如果表中有记录,它显然会跳过已经采用的ID值.)其他RDBMS供应商有自己的语法,但效果大致相同,所以在系统帮助文件或互联网中查找"reseed identity"或"reseed autonumber".

再次:这是针对特殊场合,而不是经常使用.不要把它放在存储过程中,让我们都来到那里.

  • 在我看来,只有在删除测试数据以准备实时数据时才应使用重新种子.几乎从不在生产系统上. (5认同)
  • “*虽然如果你在表中有记录,它显然会跳过已经被采用的 ID 值*” - 我的经验是事实并非如此,当你尝试执行时,你会得到重复的主键约束冲突执行插入(在 SQL Server 2008 上测试)。您需要将其重新设定为表中的最大标识值。它将在下一次插入时分配下一个值(即预增量)。 (3认同)

BCS*_*BCS 5

我认为没有任何要求自动编号的键是顺序的。事实上,我不认为他们可以被要求是:

  • 事务 a 开始并插入

  • 事务 b 开始并插入

  • 事务a中止

    你有一个洞。无事可做。