在Oracle中使用FK查询FOR UPDATE NOWAIT

hna*_*ger 5 sql oracle locking oracle11g

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

假设一个Oracle会话S1获得SELECT FOR UPDATE NOWAIT在创纪录的锁tab1t_id=123.

NOWAITs1仍然保持锁定时tab1,另一个会话s2可以tab2tab2.t_id=123(FK)更新记录吗?

Mic*_*nic 0

正如注释中所指出的,使用锁定 read ( SELECT ... FOR UPDATE) 语句发出的行锁不会传播到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;
Run Code Online (Sandbox Code Playgroud)

以下脚本使用 pragmaAUTONOMOUS_TRANSACTION来发出新事务,成功执行(例如在 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;
Run Code Online (Sandbox Code Playgroud)

因此,可以更改 中的其他行以及指向 中锁定行的tab1外键列。tab2tab1

正如预期的那样,尝试更新锁定的行:

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;
Run Code Online (Sandbox Code Playgroud)

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

ORA-00060: 等待资源时检测到死锁