我有一个表tab1 (t_id, status)
和表tab2 (id, t_id, status)
,其中t_id.tab2
的外键引用tab1.t_id
。
假设Oracle会话s1使用SELECT FOR UPDATE NOWAIT
对tab1
中的记录进行t_id=123
锁定。
虽然NOWAIT
上的s1仍然保留tab1
次锁定,但tab2
tab2.t_id=123
中的另一个会话s2会更新记录吗?
答案 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