插入失败,但身份值增加,这会破坏原子性规则吗?

时间:2012-07-19 15:30:40

标签: sql sql-server postgresql acid

当我从大型Excel中将数据导入新表时,如果一个记录失败,则不会导入任何内容。我认为这是可以的,因为它符合原子性规则。但是,当我修复源数据错误并再次导入时,标识列不是从1开始,而是从一个大值开始。

例如

create table #test (id int identity(1,1), name varchar(4) default '')

insert into #test (name) values('1 insert will failed');
select ident_current('#test') as ident_current
insert into #test (name) values('2 insert will failed');
select ident_current('#test') as ident_current

insert into #test (name) values('3 OK');
select ident_current('#test') as ident_current

select * from #test

drop table #test

结果

id          name 
----------- ---- 
3           3 OK

Wikipedia descripbe ACID如下

  

原子性

     

Atomicity要求每个事务都是“全有或全无”:如果事务的一部分失败,整个事务失败, 数据库状态保持不变 。原子系统必须保证每种情况下的原子性,包括电源故障,错误和崩溃。

因此,如果插入失败,SQL Server似乎不会让数据库状态(标识值)保持不变,那么,这是否会破坏ACID规则?

BTW,当插入失败时,PostgreSQL不会让身份(串行)值增长。 (更新:仅有时,请参阅评论。不要依赖于此。)。

test=# create table AutoIncrementTest (id serial not null, name varchar(4));
NOTICE:  CREATE TABLE will create implicit sequence "autoincrementtest_id_seq" for serial column "autoincrementtest.id"
CREATE TABLE
test=# insert into autoincrementtest(name) values('12345');
ERROR:  value too long for type character varying(4)
test=# insert into autoincrementtest(name) values('12345');
ERROR:  value too long for type character varying(4)
test=# insert into autoincrementtest(name) values('1234');
INSERT 0 1
test=# select * from autoincrementtest;
 id | name
----+------
  1 | 1234

3 个答案:

答案 0 :(得分:5)

由于身份值不是物理存储在您可以访问的数据库的任何部分中的东西,我不同意这会破坏原子性。如果您不想“打破原子性”,或者您不关心间隙(您不应该),还有其他方法可以做到这一点(例如,使用可序列化的事务并为新行获取MAX(col)+1 )。

答案 1 :(得分:3)

是的,所以不要依赖于MSSQL Server的连续值。

我建议依靠连续的身份值本身,任何引擎都是一种脆弱和天真的方法。这可能总是作为后续删除的结果而发生。

我认为这种与纯粹ACID合规性的偏差允许在MS SQL Server中进行性能优化。

答案 2 :(得分:1)

根据此公式,原子性保证数据库状态保持不变。问题是我们对数据库状态的意思。

只要您理解“身份插入”的SQL概念既不声称也不保证身份列将是顺序的,则没有问题。当你考虑身份插入时,它确实需要重新考虑SQL保证什么,但是因为我们知道在所提到的情况下这可能会失败,所以它并不能真正保证是NEXT值。

在插入之前,标识列的“下一个”值仅保证大于当前值 - 而不是它是下一个值。这仍然是事后的状态。