示例查询:
insert into book (id, name, count)
values(book_id_seq.nextval , 'stack', (select count(*) from book)+1);
这会有任何数据不一致('count'
列)或在多线程环境中受到竞争条件的影响吗?
答案取决于ISOLATION LEVEL上的设置 - 使用默认设置read committed
事务执行的每个查询只能查看在查询开始之前提交的数据
这意味着在您的情况下,如果两个不同的会话并行执行此插入
-- session 1
insert into book (id,name,cnt) values (2,'a',(select max(cnt)+1 from book));
-- session 2
insert into book (id,name,cnt) values (3,'b',(select max(cnt)+1 from book));
你会看到(两个会话提交后)两个新记录中的相同计数。
ID NAME CNT
---------- ---------- ----------
1 i 1
2 a 2
3 b 2
无论如何,如果你在具有唯一约束的列(例如主键)上执行此操作 - 在任何情况下都不应该这样做!行为是不同的(使用序列来为concurent插入ID分配 - 对于严格的单个会话运行,max(id)+1 approch是正常的)。
-- session 1
insert into book (id,name,cnt) values ((select max(id)+1 from book),'a',1);
-- session2
insert into book (id,name) values ((select max(id)+1 from book),'b');
这里会话2正在等待锁定,直到会话1提交,然后您收到错误:
ORA-00001: unique constraint (REPORTER.SYS_C0026759) violated
所以只有第一个插入成功。
所以简短的回答是没有不一致的。如果您不希望在更多记录中看到相同的计数,则可以捕获它在CNT
列上定义唯一约束。但是againg不这样做 - 表中的CNT专栏设计不合理。该值不应存储,而是在查询中计算(例如,作为ID
lower比记录ID
的记录计数)。
我不确定你的意思是“安全”。您提出的查询:
insert into book (id, name, count)
values(book_id_seq.nextval , 'stack', (select count(*) from book)+1);
将在数据库的多个连接同时执行相同的语句但可能不会给出您想要的结果的环境中成功运行,尽管我必须承认我不知道您期望的结果。
让我们考虑以下示例:
ID=1 NAME='stack' count=1
ID=2 NAME='stack' COUNT=1
ID=3 NAME='stack' COUNT=3
所以我们的BOOK表现在包含了
ID NAME COUNT
1 stack 1
2 stack 1
3 stack 3
语句的实际时间无关紧要 - 语句执行和提交之间的时间可能是几微秒或几小时。重要的是语句执行和提交的顺序。
祝你好运。