在Oracle中使用FK查询FOR UPDATE NOWAIT

时间:2015-10-27 09:51:27

标签: sql oracle oracle11g locking

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

假设Oracle会话s1使用SELECT FOR UPDATE NOWAITtab1中的记录进行t_id=123锁定。

虽然NOWAIT上的s1仍然保留tab1次锁定,但tab2 tab2.t_id=123中的另一个会话s2会更新记录吗?

1 个答案:

答案 0 :(得分:0)

正如在注释中指出的那样,使用锁定读取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;

以下脚本使用AUTONOMOUS_TRANSACTION pragma发出新事务,成功执行(例如在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