2

想象一下我有这个简单的表:

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 在哪里/如何管理事务,以便在我还没有提交事务时知道我违反了约束。

4

4 回答 4

8

Oracle 创建一个索引来强制执行主键约束(默认情况下是唯一索引)。当 Session A 插入第一行时,索引结构会更新,但不会提交更改。当会话 B 尝试插入第二行时,索引维护操作注意到索引中已经存在具有该特定键的挂起条目。会话 B 无法获取保护共享索引结构的锁存器,因此它将阻塞直到会话 A 的事务完成。此时,会话 B 将能够获取锁存器并对索引进行自己的修改(因为 A 回滚),或者它会注意到另一个条目已被提交,并将引发唯一约束冲突(因为 A 已提交)。

于 2011-08-15T18:40:17.980 回答
2

这是因为强制主键约束的唯一索引。即使尚未提交对数据块的插入,尝试将重复条目添加到索引中也不会成功,即使它是在另一个会话中完成的。

于 2011-08-15T18:38:52.147 回答
1

仅仅因为您还没有完成提交并不意味着第一条记录还没有发送到服务器。Oracle 已经知道您打算插入第一条记录。当您插入第二条记录时,Oracle 肯定知道如果没有违反约束,这将永远不会成功,因此它会拒绝。

如果另一个用户要插入第二条记录,如果第一条记录尚未提交,Oracle 将接受它。如果第二个用户在您之前提交,您的提交将失败。

于 2011-08-15T18:37:52.130 回答
0

除非特定约束是“延迟的”,否则将在语句执行时检查它。如果延迟,将在交易结束时进行检查。我假设您没有推迟您的 PRIMARY KEY,这就是为什么您甚至在提交之前就违反了。

如何真正做到这一点是一个实现细节,并且在不同的数据库系统甚至同一系统的版本之间可能会有所不同。应用程序开发人员可能不应该对此做出太多假设。在 Oracle 的案例中,PRIMARY KEY 出于性能原因使用底层索引,而有些系统甚至不需要索引(如果您可以忍受相应的性能影响)。

顺便说一句,可延迟的 Oracle PRIMARY KEY 约束依赖于非唯一索引(与使用唯一索引的不可延迟 PRIMARY KEY 相比)。

- - 编辑 - -

我刚刚意识到你甚至没有提交第一个 INSERT。我认为贾斯汀的回答很好地解释了本质上是锁争用如何导致其中一个事务停止。

于 2011-08-15T19:18:46.823 回答