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

Liu*_* 刘研 3 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
Run Code Online (Sandbox Code Playgroud)

结果

id          name 
----------- ---- 
3           3 OK
Run Code Online (Sandbox Code Playgroud)

维基百科描述了ACID如下

原子性

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

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

顺便说一下,当插入失败时,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
Run Code Online (Sandbox Code Playgroud)

Aar*_*and 5

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