我有一个带有SQL插件的.net事务到SQL Server 2005数据库。该表具有标识主键。
当事务中发生错误时,将调用Rollback()
。行插入正确回滚,但是下次将数据插入表时,标识会增加,就好像回滚从未发生过一样。所以基本上在身份序列中存在差距。有没有办法让Rollback()
方法回收丢失的身份?
我没有以正确的方式接近这个吗?
答案 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)
我认为没有要求自动编号键是顺序的。事实上,我不认为他们可以被要求:
交易中止
你得到一个洞。无所事事。答案 6 :(得分:1)
Muhan尝试在执行此事务的许多同时连接的上下文中考虑它,而不是一次一个。有些会失败,有些会成功。您希望SQL Server专注于在新请求进入时运行,而不是维护无间隙标识列。 IMO(价值观上的差距)绝对不值得花时间。
答案 7 :(得分:1)
没有。序列实施使用自治事务。在Oracle中,自治事务曾经是dbms的内部事务,但现在暴露给您自己使用(并且经常使用不正确)
PRAGMA AUTONOMOUS_TRANSACTION;'