Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/70.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql Oracle—Oracle如何管理特定于事务的DML语句_Sql_Oracle_Oracle10g_Dml - Fatal编程技术网

Sql Oracle—Oracle如何管理特定于事务的DML语句

Sql Oracle—Oracle如何管理特定于事务的DML语句,sql,oracle,oracle10g,dml,Sql,Oracle,Oracle10g,Dml,假设我有一张简单的桌子: Table Name: Table1 Columns: Col1 NUMBER (Primary Key) Col2 NUMBER 如果我在表1中插入一条没有提交的记录 INSERT INTO Table1 (Col1, Col2) Values (100, 1234); Oracle如何知道下一条INSERT语句违反了PK约束,因为尚未向数据库提交任何内容 INSERT INTO Table1 (Col1, Col2) Values

假设我有一张简单的桌子:

Table Name: Table1
Columns:    Col1 NUMBER (Primary Key)
            Col2 NUMBER
如果我在表1中插入一条没有提交的记录

INSERT INTO Table1 (Col1, Col2) Values (100, 1234);
Oracle如何知道下一条INSERT语句违反了PK约束,因为尚未向数据库提交任何内容

INSERT INTO Table1 (Col1, Col2) Values (100, 5678);

Oracle在何处/如何管理事务,以便在我尚未提交事务时知道我违反了约束。

仅因为您尚未提交,并不意味着第一条记录尚未发送到服务器。Oracle已经知道您要插入第一条记录的意图。当您插入第二条记录时,Oracle肯定知道,如果不违反约束,这是不可能成功的,所以它拒绝了


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

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

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

除非某个特定约束被“延迟”,否则将在语句执行时对其进行检查。如果延迟,将在事务结束时进行检查。我假设您没有延迟主键,这就是为什么您在提交之前就收到了违规

如何真正做到这一点是一个实现细节,不同的数据库系统甚至同一系统的版本可能会有所不同。应用程序开发人员可能不应该对此做太多假设。在Oracle的情况下,主键使用基础索引是出于性能原因,而有些系统甚至不需要索引(如果您可以承受相应的性能损失)

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

---编辑---


我才意识到你连第一次插入都没有。我认为Justin的回答很好地解释了锁争用是如何导致其中一个事务暂停的。

Oracle在哪里/如何管理它?在某种类型的系统表中?@contactmatt-在索引结构本身中。就像表块中的每一行都有一个锁标志,这样Oracle就不需要单独的锁管理器一样,索引块中也有类似的结构。+1。解释得很好。我总是问别人这样一个问题:“这些信息(索引项、表项)是在哪里写的?在重做/撤消日志中?”还有一个问题,当我用insert语句测试我的问题时,它们都在同一个事务和会话中。您通过在两个不同的会话中演示一个示例来回答问题。同一个会话呢?@contactmatt-在同一个会话中处理多个语句时会更容易,因为前面语句所做的更改在同一个事务中完全可见。您的第二条insert语句只需访问索引中的相应块(事务已经为其锁定),查看索引中的数据,并抛出异常。第二条语句不知道重复行是插入到同一事务中还是插入到几个月前提交的事务中。我做了一个小测试,事实上:第二个事务将等待(锁定),直到您提交或回滚第一个会话。不完全是-第二个会话挂起,等待第一笔交易的结果。试试看。你说的“
所以它拒绝了。
”是什么意思?您提到的是错误消息吗?我确实尝试过(请参阅我对另一个答案的评论),您是正确的:第二个会话将挂起,直到第一个会话被提交/回滚。使用
拒绝
时,我预期会违反约束。