【问题标题】:Can a table be locked by another table?一张桌子可以被另一张桌子锁定吗?
【发布时间】:2015-06-20 20:49:20
【问题描述】:
我们在 oracle 11g 数据库中遇到了关于表锁定的问题。
我们有一个通过 sql*plus 执行的过程,它截断一个表,比如说 table1。
我们有时会收到 ORA-00054: resource busy and acquire with NOWAIT error during the procedure at the part of the part of the table is to betruncated. 我们有时会收到 ORA-00054: resource busy and acquire with NOWAIT error during the procedure at the part of the part of the table is to betruncated.我们有一个位于 tomcat 服务器中的 webapp,当重新启动时(从 tomcat 终止与数据库的会话),该过程可以重新成功执行。
在webapp的源代码中没有使用table1,甚至在select中也没有使用,但是table1的很多父表都是。
那么是否有可能是对其父表之一的未提交更新导致锁定?如果是这样,关于如何测试它的任何建议?
在我们遇到问题时,我已经与 DBA 进行了核对,但他无法获取阻塞过程的会话和导致锁定的语句。
【问题讨论】:
标签:
oracle
locking
ora-00054
【解决方案1】:
是的,父表的更新将获得子表的锁定。下面是一个证明这是可能的测试用例。
查找和跟踪特定的间歇性锁定问题可能会很痛苦。即使您无法追踪特定条件,修改任何代码以避免并发 DML 和 DDL 也是一个好主意。它不仅会导致锁定问题,还会破坏SELECT 语句。
如果删除并发是不可能的,您可能至少想要启用 DDL_LOCK_TIMEOUT 以便truncate 语句将等待锁定而不是立即失败:alter session set ddl_lock_timeout = 100000;
--Create parent/child tables, with or without an indexed foreign key.
create table parent_table(a number primary key);
insert into parent_table values(1);
insert into parent_table values(2);
create table child_table(a number references parent_table(a));
insert into child_table values(1);
commit;
--Session 1: Update parent table.
begin
loop
update parent_table set a = 2 where a = 2;
commit;
end loop;
end;
/
--Session 2: Truncate child table. Eventulaly it will throw this error:
--ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired
begin
loop
execute immediate 'truncate table child_table';
end loop;
end;
/
【解决方案2】:
关于如何测试它的任何建议?
当您收到ORA-00054: resource busy and acquire with NOWAIT 错误时,您可以检查阻塞会话。
当一个会话持有一个对象的排他锁并且在另一个会话想要更新相同数据之前不释放它时,就会发生阻塞会话。这将阻止第二个,直到第一个执行 COMMIT 或 ROLLBACK。
SELECT
s.blocking_session,
s.sid,
s.serial#,
s.seconds_in_wait
FROM
v$session s
WHERE
blocking_session IS NOT NULL;
例如,请参阅我的类似答案here 和here。