想象一下,我有这个简单的表格:
Table Name: Table1
Columns: Col1 NUMBER (Primary Key)
Col2 NUMBER
如果我将记录插入Table1而没有提交...
INSERT INTO Table1 (Col1, Col2) Values (100, 1234);
Oracle如何知道下一个INSERT语句违反了PK约束,因为尚未向数据库提交任何内容。
INSERT INTO Table1 (Col1, Col2) Values (100, 5678);
Oracle在哪里/如何管理交易,以便在我尚未提交交易时知道我违反了约束。
答案 0 :(得分:8)
Oracle创建一个索引来强制执行主键约束(默认情况下为唯一索引)。会话A插入第一行时,将更新索引结构,但不会提交更改。当会话B尝试插入第二行时,索引维护操作会注意到索引中已存在具有该特定键的挂起条目。会话B无法获取保护共享索引结构的锁存器,因此它将阻塞直到会话A的事务完成。此时,会话B将能够获取锁存器并对索引进行自己的修改(因为A回滚)或者它将注意到另一个条目已经提交并将抛出唯一的约束违规(因为A已提交) )。
答案 1 :(得分:2)
这是因为强制主键约束的唯一索引。即使尚未提交插入数据块,但是将重复条目添加到索引中的尝试也不会成功,即使它是在另一个会话中完成的。
答案 2 :(得分:1)
仅仅因为您尚未完成提交但并不意味着第一条记录尚未发送到服务器。 Oracle已经知道你有意插入第一条记录。当您插入第二条记录时Oracle确定无法在没有约束违规的情况下成功,所以它拒绝。
如果另一个用户要插入第二条记录,如果第一条记录尚未提交,Oracle将接受该记录。如果第二个用户在您提交之前提交,则提交将失败。
答案 3 :(得分:0)
除非特定约束是“延迟”,否则将在语句执行时检查它。如果延期,将在交易结束时进行检查。我假设你没有推迟你的PRIMARY KEY,这就是你甚至在提交之前就遭到违规的原因。
这是如何真正完成的是一个实现细节,并且可能因不同的数据库系统甚至同一系统的版本而异。应用程序开发人员可能不应该对它做太多假设。在Oracle的情况下,PRIMARY KEY出于性能原因使用底层索引,而有些系统甚至不需要索引(如果你可以使用相应的性能命中)。
BTW,可延迟的Oracle PRIMARY KEY约束依赖于非唯一索引(与使用唯一索引的不可延迟的PRIMARY KEY相比)。---编辑---
我刚刚意识到你甚至没有提交第一个INSERT。我认为Justin的答案很好地解释了什么本质上是一个锁争用导致其中一个事务停滞。