在 Oracle 中 FK 的情况下查询 FOR UPDATE NOWAIT

Query on FOR UPDATE NOWAIT in case of FK in Oracle

我有一个 table tab1 (t_id, status) 和 table tab2 (id, t_id, status) 其中 t_id.tab2 有外键引用 tab1.t_id.

假设 Oracle 会话 s1 获取 SELECT FOR UPDATE NOWAIT 锁定 tab1 中的记录 t_id=123

虽然 NOWAIT 锁仍由 s1 在 tab1 上持有,但另一个会话 s2 可以使用 tab2.t_id=123 更新 tab2 中的记录吗(FK)?

正如评论中指出的那样,使用 locking read (SELECT ... FOR UPDATE) 语句发出的行锁不会传播到子 table 声明 FOREIGN KEY 的地方。

这里有一个例子可以证明这一点:

-- Set up schema
CREATE TABLE tab1 (t_id NUMBER(10), status VARCHAR2(10), PRIMARY KEY (t_id));
CREATE TABLE tab2 (id NUMBER(10), t_id NUMBER(10), status VARCHAR2(10), 
                  PRIMARY KEY (id),
                  CONSTRAINT fk_tab1 FOREIGN KEY (t_id) REFERENCES tab1 (t_id));
INSERT INTO tab1 (t_id, status) VALUES (123, 'Status1');
INSERT INTO tab1 (t_id, status) VALUES (234, 'Status1');
INSERT INTO tab2 (id, t_id, status) VALUES (1, 123, 'Status2');
INSERT INTO tab2 (id, t_id, status) VALUES (2, 234, 'Status2');
COMMIT;

以下脚本成功执行(例如在 Oracle SQLDeveloper 中):

SET autocommit 0;
SELECT * FROM tab1 WHERE t_id=123 FOR UPDATE NOWAIT;
DECLARE
  PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
  UPDATE tab1 SET status = 'Status2' WHERE t_id = 234;
  UPDATE tab2 SET t_id = 234, status = 'Status2' WHERE t_id = 123;
  COMMIT;
END;

因此,可以更改 tab1 中的其他行以及 tab2 中指向 tab1.

中锁定行的外键列

不出所料,正在尝试更新锁定的行:

SELECT * FROM tab1 WHERE t_id=123 FOR UPDATE NOWAIT;
DECLARE
  PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
  UPDATE tab1 SET status = 'Status2' WHERE t_id = 123;
  COMMIT;
END;

... 将失败并显示错误消息:

ORA-00060: deadlock detected while waiting for resource