以下代码会导致死锁还是应该没有任何问题?我有类似的东西,它的工作,但我认为它不会。我认为父进程的锁会导致子进程的死锁,但似乎不是。
如果有效,为什么?我的猜测是嵌套的FOR UPDATE没有遇到死锁,因为它足够聪明地意识到它是由具有当前锁的相同过程调用的。
如果FOO_PROC不是嵌套程序,这会是一个死锁吗?
DECLARE
FOO_PROC(c_someName VARCHAR2) as
cursor c1 is select * from awesome_people where person_name = c_someName FOR UPDATE;
BEGIN
open c1;
update awesome_people set person_name = UPPER(person_name);
close c1;
END FOO_PROC;
cursor my_cur is select * from awesome_people where person_name = 'John Doe' FOR UPDATE;
BEGIN
for onerow in c1 loop
FOO_PROC(onerow.person_name);
end loop;
END;
答案 0 :(得分:3)
它不会导致死锁。这只能在两个会话更新同一行时发生,因为它们采用乐观锁定策略。这是发生的事情
一些测试数据:
SQL> select * from t23
2 /
PERSON_NAME
-----------------------------------------------------------------------------
Fox in socks
Mr Knox
Sam-I-Am
The Lorax
John Doe
SQL>
这是你的匿名(使用更正的sybtax):.
SQL> declare
2 cursor c_jd is
3 select *
4 from t23
5 where person_name = 'John Doe'
6 for update of person_name;
7 procedure foo_proc
8 ( p_name in t23.person_name%type)
9 is
10 cursor c_fp is
11 select *
12 from t23
13 where person_name = p_name
14 for update of person_name;
15 r_fp c_fp%rowtype;
16 begin
17 open c_fp;
18 fetch c_fp into r_fp;
19 update t23
20 set person_name = upper(r_fp.person_name)
21 where current of c_fp;
22 close c_fp;
23 end foo_proc;
24 begin
25 for onerow in c_jd loop
26 foo_proc(onerow.person_name);
27 end loop;
28 end;
29 /
PL/SQL procedure successfully completed.
SQL>
这就是结果
SQL>从t23中选择* 2 /
PERSON_NAME
-----------------------------------------------------------------------------
Fox in socks
Mr Knox
Sam-I-Am
The Lorax
JOHN DOE
SQL>
它成功了吗?因为FOR UPDATE是会话级锁定。这两个锁是从同一个会话发出的,因此Oracle足够智能,可以在不发生争用的情况下解决它们。如果你要在FOO_PROC()声明一个PRAGMA AUTONOMOUS_TRANSACTION之类的东西,它会投掷
ORA-00060: deadlock detected while waiting for resource
在同一会话中两次调用FOR UPDATE并不会以这种方式失败的事实是一个重要的架构设计。在不查看源代码的情况下,无法判断过程是否发出锁定。因此,当PROC_A()调用PROC_B()时,它不知道该过程是否发出锁定。但PROC_A()可以发出自己的锁,确信此操作不会导致PROC_B()失败。这是一件好事,因为它坚持Demeter法并减少耦合。
当然,你的场景是人为的,在代码审查中会被拒绝,但这是一个不同的问题!
修改强>
你确定吗? AUTONOMOUS_TRANSACTION pragma恰恰意味着FOO_PROC()在其自己的离散会话中运行,因此无法获得锁定:“为了测试这个,我做了FOO_PROC 自治,它没有碰到一个 僵局;是因为它在 同一个会议?“
SQL> declare
2 cursor c_jd is
3 select *
4 from t23
5 for update of person_name;
6 procedure foo_proc
7 ( p_name in t23.person_name%type)
8 is
9 pragma autonomous_transaction;
10 cursor c_fp is
11 select *
12 from t23
13 where person_name = p_name
14 for update of person_name;
15 r_fp c_fp%rowtype;
16 begin
17 dbms_output.put_line('Inside FP');
18 open c_fp;
19 fetch c_fp into r_fp;
20 update t23
21 set person_name = upper(r_fp.person_name)
22 where current of c_fp;
23 close c_fp;
24 commit;
25 end foo_proc;
26 begin
27 for onerow in c_jd loop
28 dbms_output.put_line('Outer loop START');
29 foo_proc(onerow.person_name);
30 dbms_output.put_line('Outer loop END');
31 end loop;
32 end;
33 /
Outer loop START
Inside FP
declare
*
ERROR at line 1:
ORA-00060: deadlock detected while waiting for resource
ORA-06512: at line 11
ORA-06512: at line 18
ORA-06512: at line 29
SQL>
(我添加了一些DBMS_OUTPUT语句来显示正在发生的事情)。
“当你说代码示例时我 提供的是不好的做法,你是什么 意思?“
我的意思是让一个循环驱动SELECT语句调用另一个从同一个表中选择的程序。实际上,它选择了同一行。一般来说,我们应该避免做不必要的工作。你已经有了这一行:为什么要再读一遍?