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

问题描述 投票:73回答:8

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

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

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

.net sql sql-server-2005 transactions identity-column
8个回答
97
投票

如果你考虑一下,自动增量号码不应该是事务性的。如果其他交易必须等待查看自动号码是否将被使用或“回滚”,则使用自动号码的现有交易将阻止它们。例如,使用表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

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

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


31
投票

如果你依赖于你的身份价值无间隙,那么是 - 你做错了。 surrogate key的全部意义是没有商业意义。

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


15
投票

如果你DELETE也行,你的序列中会出现间隙。

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


6
投票

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


6
投票

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

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

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

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

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


4
投票

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

  • 事务a开始和插入
  • 事务b启动和插入
  • 交易中止 你得到一个洞。无所事事。

1
投票

Muhan尝试在执行此事务的许多同时连接的上下文中考虑它,而不是一次一个。有些会失败,有些会成功。您希望SQL Server专注于在新请求进入时运行,而不是维护无间隙标识列。 IMO(价值观上的差距)绝对不值得花时间。


1
投票

序号实施使用自主交易。在Oracle中,自治事务曾经是dbms的内部事务,但现在暴露给您自己使用(并且经常使用不正确)

PRAGMA AUTONOMOUS_TRANSACTION;' 
© www.soinside.com 2019 - 2024. All rights reserved.