我有一个带有 SQL 插入到 SQL Server 2005 数据库的 .net 事务。该表具有标识主键。
当事务中发生错误时,Rollback()
调用。行插入正确回滚,但是下次我将数据插入表时,标识会增加,就好像回滚从未发生过一样。所以本质上在身份序列中存在差距。有没有办法让该Rollback()
方法恢复丢失的身份?
我不是以正确的方式接近这个吗?
我有一个带有 SQL 插入到 SQL Server 2005 数据库的 .net 事务。该表具有标识主键。
当事务中发生错误时,Rollback()
调用。行插入正确回滚,但是下次我将数据插入表时,标识会增加,就好像回滚从未发生过一样。所以本质上在身份序列中存在差距。有没有办法让该Rollback()
方法恢复丢失的身份?
我不是以正确的方式接近这个吗?
如果您考虑一下,自动增量数字不应该是事务性的。如果其他事务必须等待查看自动编号是否将被使用或“回滚”,它们将被使用自动编号的现有事务阻止。例如,考虑下面我的伪代码,表 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 的自动编号。
这是一个功能,而不是一个错误。如果您需要它们紧密顺序,我建议使用另一种方案来生成自动编号。
如果你依赖于你的身份价值观是无缝的,那么是的——你做错了。代理键的全部意义在于没有商业意义。
而且,不,没有办法改变这种行为(除了滚动你自己的自动增量,并遭受阻塞其他插入的性能后果)。
如果您也DELETE
排成一排,您的序列中也会出现空白。
序列必须是唯一的,但它们不需要是连续的。它们单调递增的事实只是实施的侥幸。
所有其他说不用担心,你应该有差距的海报都是对的。如果该数字具有商业意义,并且该意义不存在空白,则不要使用标识列。
仅供参考,如果您出于某种原因想要消除差距,大多数数据库都有办法将自动编号重新设置为您选择的编号。这很麻烦,如果您发现自己需要定期这样做,那么您绝对不应该使用自动编号/身份字段,如上所述。但这是在 SQL Server 中执行此操作的代码:
DBCC CHECKIDENT('Product', RESEED, 0)
这会将产品表设置为从 1 开始(尽管如果表中有记录,它显然会跳过已经采用的 ID 值。)其他 RDBMS 供应商有自己的语法,但效果大致相同,所以在系统帮助文件或互联网中查找“重新种子身份”或“重新种子自动编号”。
再说一遍:这是用于特殊场合,而不是经常使用。不要把它放在一个存储过程中,让我们都过来。
据我所知,插入的行声明了自动编号,并且在回滚时,该编号将永远丢失。如果您依赖于排序中的自动编号,您可能需要考虑您正在使用的方法。
我认为没有任何要求自动编号的键是连续的。事实上,我不认为他们可以被要求:
事务 a 开始并插入
事务 b 开始并插入
交易中止
你得到一个洞。无事可做。
Muhan 尝试在执行此事务的许多同时连接的上下文中考虑它,而不是一次一个。有些会失败,有些会成功。您希望 SQL Server 专注于在新请求进入时运行它们,而不是维护无间隙的标识列。IMO it(价值观的差距)绝对不值得花时间在上面。
不,序列实现使用自治事务。在 Oracle 中,自治事务曾经在 dbms 内部,但现在公开供您自己使用(并且经常被错误地使用)
PRAGMA AUTONOMOUS_TRANSACTION;'