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

时间:2008-11-11 23:05:59

标签: .net sql sql-server-2005 transactions identity-column

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

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

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

8 个答案:

答案 0 :(得分:97)

如果您考虑一下,自动递增编号不应该是交易性的。如果其他交易必须等待查看自动号码是否将被使用或“回滚”,则使用自动号码的现有交易将阻止它们。例如,考虑我的伪代码,使用表A的表A使用ID列的自动编号字段:

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。如果您需要紧密顺序,我建议使用另一种方案来生成自动数字。

答案 1 :(得分:31)

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

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

答案 2 :(得分:15)

如果你DELETE行,你的序列也会出现空白。

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

答案 3 :(得分:6)

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

答案 4 :(得分:6)

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

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

DBCC CHECKIDENT('Product',RESEED,0)

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

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

答案 5 :(得分:4)

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

  • 事务a启动并插入
  • 事务b启动并插入
  • 交易中止

    你得到一个洞。无所事事。

答案 6 :(得分:1)

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

答案 7 :(得分:1)

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

PRAGMA AUTONOMOUS_TRANSACTION;'