Oracle - 从子表中删除行会锁定父表

4
我们在Oracle 11.2g中遇到了死锁问题。死锁发生的一个潜在原因是从子表中删除时锁定了父表。我查阅了Oracle文档,但没有找到任何关于这种类型锁的规范说明。非常感谢您提供任何解释或文档参考。
以下是代码:
CREATE TABLE table_parent (a NUMBER PRIMARY KEY);
CREATE TABLE table_child (b NUMBER, a NUMBER,PRIMARY KEY (b), CONSTRAINT fk_relation FOREIGN KEY (a) REFERENCES table_parent(a));

INSERT INTO table_parent VALUES (1);
INSERT INTO table_parent VALUES (2);
INSERT INTO table_child VALUES (1,1);
INSERT INTO table_child VALUES (2,1);
INSERT INTO table_child VALUES (3,1);
INSERT INTO table_child VALUES (4,1);

COMMIT;

然后从子表中删除1条记录。

DELETE FROM table_child WHERE b=4;

在执行提交之前,我们查看V$LOCK表。这里有两个新的锁“table_child”和“table_parent”,类型为“TM”。

以下是查看V$LOCK表的查询。

SELECT O.OWNER, O.OBJECT_ID, O.OBJECT_NAME, O.OBJECT_TYPE, L.TYPE
FROM DBA_OBJECTS O, V$LOCK L
WHERE O.OBJECT_ID = L.ID1;

问题是为什么“table_parent”被锁定了?

3个回答

2

在 table_child(a) 列上添加索引 - 你总是为外键列建立索引,就是为了这个原因。


2
为了维护跨多行的约束,比如外键,有时候需要对事务进行序列化处理(即一个DBMS需要将某些事务强制串行化)。需要进行序列化处理的时刻取决于事务对相关表格所做更改的类型。理论上,只有当更改的类型可能会违反多行约束时,DBMS才需要自动对事务进行序列化处理(例如通过获取各种类型的锁)。(在提供快照隔离级别的DBMS中,Oracle就是这样做的。)
现在,在外键的情况下,我们需要问自己:什么情况下会违反外键?有四种情况:
- 删除父行:如果子行仍存在,则会违反FK。 - 更新父行的主键:如果子行仍然指向旧值,则会违反FK。 - 插入子行:如果行指向不存在的父行,则会违反FK。 - 更新子行的FK列值:如果新列值指向不存在的父行,则会违反FK。
所有涉及的(2)个表格上的其他类型的交易都不能违反FK。因此,在您的情况下,删除子行时,不需要进行序列化。但是Oracle可能有一些“实现特定”的原因,强制它执行某种类型的锁定。

我曾经看到过另一种情况,即Oracle也执行这种“不必要”的锁定:您可以在https://forums.oracle.com/forums/thread.jspa?messageID=10050753&#10050753找到它

Toon


谢谢您的回复。您的解释似乎非常合乎逻辑。这种锁有名称或术语吗?顺便说一下,在“锁定和外键”官方文档中有一个非常令人困惑的注释。 注:“子表上的DML不会在父表上获取表锁。” http://docs.oracle.com/cd/E11882_01/server.112/e16508/consist.htm#autoId24 - goldenhordes
确保正确的约束验证(因此事务串行化)所需的锁的学术术语是:谓词锁。然而,DBMS供应商并未实现谓词锁的概念。因此,他们转而锁定数据对象(表和/或索引条目)。 - Toon Koppelaars

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接