关于不同数据库中的插入机制,我有一个问题。假设一个表具有自动生成的单列主键(如标识列),插入新记录时整个表是否会被锁定?如果插入花费太多时间,其他交易是否还要等待更多?
答案 0 :(得分:3)
插入不会锁定表格。在您提交之前,插入的记录对其他会话不可见。
答案 1 :(得分:3)
您的问题与您插入具有任何唯一约束的表格的任何情况相关。如果没有索引,并且在表中插入一行,则您希望数据库需要锁定整个表 - 否则可能会在多用户系统中插入重复项。
但是,Oracle始终使用索引来限制唯一约束。这意味着列的数据始终排序,并且可以快速轻松地确定是否已存在冲突行。为了防止尝试同时插入相同值的多个会话,Oracle将仅锁定该值的索引中的块 - 这样,您将不会争用整个表,仅针对特定值'插入。由于索引查找通常非常快,因此只需要在非常短的时间内保持锁定。
(但是现在,你可能会问,如果一个会话插入一个值但是没有立即提交怎么办?如果另一个会话试图插入相同的值怎么办?答案是,第二个会话将等待。这是因为它将在同一索引块上请求锁定,但由于第一个会话尚未提交,该块仍将被锁定。它必须等待,因为它无法知道第一个会话是提交还是回滚。)
答案 2 :(得分:3)
默认情况下,Oracle使用行级锁。
这些锁仅针对编写器阻塞(更新,删除,插入等)。这意味着当表格大量更新,删除等时,select将一直有效。
例如,设为tableA(col1编号,col2编号),其中包含此数据:
col1 | col2
1 | 10
2 | 20
3 | 30
如果用户John在time1
处发布:
update tableA set col2=11 where col1=1;
将锁定row1。
在time2
用户标记处发出
update tableA set col2=22 where col1=2;
更新将起作用,因为第2行未锁定。
现在该表在数据库中查找:
col1 | col2
1 | 11 --locked by john
2 | 22 --locked by mark
3 | 30
对于Mark表是(他没有看到未经修改的变化)
col1 | col2
1 | 10
2 | 22
3 | 30
对于John表是:(他没有看到未经修改的变化)
col1 | col2
1 | 11
2 | 20
3 | 30
如果标记尝试time3
:
update tableA set col2=12 where col1=1;
当John发出time4
时,他的会话将一直持续到commit
。(回滚也会解锁行,但更改将会丢失)
表是(在db中,在时间4):
col1 | col2
1 | 11
2 | 22 --locked by mark
3 | 30
Immediatley,在John的提交之后,row1被解锁并且标记的更新将完成这项工作:
col1 | col2
1 | 12 --locked by mark
2 | 22 --locked by mark
3 | 30
让我们在time5标记一个rollbak:
col1 | col2
1 | 11
2 | 20
3 | 30
插入案例更简单,因为插入的行被锁定,但其他用户也看不到它们,因为它们未被提交。当用户提交时,他也会释放锁,因此,其他用户可以查看这些行,更新它们或删除它们。
编辑:正如Jeffrey Kemp解释的那样,当你有PK(它在Oracle中使用唯一索引实现)时,如果用户试图插入相同的值(那么,我们会有重复),锁定将在索引中发生。第二个会话将被阻止,直到第一个会话结束,因为它尝试在同一个地方写入。如果第一个会话提交,第二个会抛出主键违反异常,将无法更改数据库。如果第一个会话执行回滚,则第二个会话将成功(如果没有出现其他问题)。
(注意:在用户John的解释中,我指的是用户John开始的会话。)