Oracle INSERT是否具有SELECT线程安全性?

问题描述 投票:0回答:2

示例查询:

insert into book (id, name, count)
values(book_id_seq.nextval , 'stack', (select count(*) from book)+1);

这会有任何数据不一致('count'列)或在多线程环境中受到竞争条件的影响吗?

sql multithreading oracle
2个回答
1
投票

答案取决于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专栏设计不合理。该值不应存储,而是在查询中计算(例如,作为IDlower比记录ID的记录计数)。


0
投票

我不确定你的意思是“安全”。您提出的查询:

insert into book (id, name, count)
values(book_id_seq.nextval , 'stack', (select count(*) from book)+1);

将在数据库的多个连接同时执行相同的语句但可能不会给出您想要的结果的环境中成功运行,尽管我必须承认我不知道您期望的结果。

让我们考虑以下示例:

  • 在第一时间,BOOK中没有条目,BOOK_ID_SEQ的“下一个数字”设置为1。
  • 在两个客户端A执行上述语句时,创建以下行: ID=1 NAME='stack' count=1
  • 在时间三,客户端B执行上述语句,创建以下行(请注意,COUNT在这里为1,因为客户端A尚未提交,因此客户端B无法“看到”客户端A已创建的行): ID=2 NAME='stack' COUNT=1
  • 在时间四,客户A提交更改。
  • 在时间五,客户B提交更改。
  • 在时间六时,客户端C执行上述语句,创建以下行: ID=3 NAME='stack' COUNT=3
  • 在时间7,客户端C提交更改。

所以我们的BOOK表现在包含了

ID    NAME    COUNT
1     stack   1
2     stack   1
3     stack   3

语句的实际时间无关紧要 - 语句执行和提交之间的时间可能是几微秒或几小时。重要的是语句执行和提交的顺序。

祝你好运。

© www.soinside.com 2019 - 2024. All rights reserved.