菜鸟oracle10-CURSOR加锁 博客分类: oracle CURSORfor updatewhere current of
程序员文章站
2024-03-23 09:10:46
...
实际工作中需要用到游标锁所以就google了又google,找到一些资料,下面贴出来一篇觉得还不错的文章: from http://hi.baidu.com/eebevkrtwgbgxzd/item/224ad35f525ec0cfd2e10c14
如下代码:
declare
-- query emp.name
cursor cur_emp
is
select empno, ename, job
from emp
where empno = 7369
for update of ename;
begin
for return_cur in cur_emp
loop
update emp
set ename = 'LHG'
where current of cur_emp;
end loop;
end;
其中的for update of ename意思是给表中的行加锁,经过测试,后面的ename可以写成该表中的任何字段,因为oracle中锁的最低级别是行锁,不存在给字段加锁。
下面是行锁的作用:
1.行锁开始于一个CURSOR的OPEN,结束于一个提交COMMIT或ROLLBACK,而并不是结束于一个CURSOR的结束(CLOSE)。
2.当在一个CURSOR中对某个表的行加锁,那么如果在这个SESSION中用另一个CURSOR操作该行记录时候会等待第一个cursor的完成提交,直到第一个cursor提交完成之后,第二个cursor中对改行的操作才会开始执行。
3.当第一个cursor中的由于操作错误而不能提交时候,第二个cursor将会一直等待下去,这样就形成了死锁。预防这种情况发生的方法是在for update of ename 之后指定NOWAIT选项,这样的话,当第二个cursor不会一直等待下去,而是出现ORA-00054 [resource busy and acquire with NOWAIT specified]的
讯息。
4.既然for update of后面的字段是随便那个字段都可以,那么可不可以不写呢?如果你没必要指定NOWAIT选项,那么后面的字段就可以不写;如果你必须指定NOWAIT选项,则必须指定至少一个字段。
5.还有一种方法是用ROWID替代WHERE CURRENT OF YOUR_CURSOR_NAME语句。
如下代码:
declare
-- query emp.name
cursor cur_emp
is
select a.deptno,
a.dname,
a.rowid,
b.rowid rowid_1
from dept a, emp b
where empno = 7369
and a.deptno = b.deptno
for update nowait;
-- local variables
v_deptno dept.deptno%type;
v_dname dept.dname%type;
v_rowid rowid;
v_rowid_1 rowid;
begin
open cur_emp;
loop
fetch cur_emp into v_deptno, v_dname, v_rowid, v_rowid_1;
exit when cur_emp%notfound;
update dept
set dname = 'abc'
where rowid = v_rowid;
update emp
set ename = 'frank'
where rowid = v_rowid_1;
end loop;
close cur_emp;
commit;
exception
when others then
rollback;
raise;
end;
由此,推荐的for update的习惯是:
NOWAIT定然跟FOR UPDATE之后。
直接用ROWID替代WHERE CURRENT OF YOUR_CURSOR_NAME语句,
尤其在相对繁习的程序里头。
COMMIT必需存在程序结尾。以防死锁成形。
EXCEPTION里的ROLLBACK是最基本的需要。
如下代码:
declare
-- query emp.name
cursor cur_emp
is
select empno, ename, job
from emp
where empno = 7369
for update of ename;
begin
for return_cur in cur_emp
loop
update emp
set ename = 'LHG'
where current of cur_emp;
end loop;
end;
其中的for update of ename意思是给表中的行加锁,经过测试,后面的ename可以写成该表中的任何字段,因为oracle中锁的最低级别是行锁,不存在给字段加锁。
下面是行锁的作用:
1.行锁开始于一个CURSOR的OPEN,结束于一个提交COMMIT或ROLLBACK,而并不是结束于一个CURSOR的结束(CLOSE)。
2.当在一个CURSOR中对某个表的行加锁,那么如果在这个SESSION中用另一个CURSOR操作该行记录时候会等待第一个cursor的完成提交,直到第一个cursor提交完成之后,第二个cursor中对改行的操作才会开始执行。
3.当第一个cursor中的由于操作错误而不能提交时候,第二个cursor将会一直等待下去,这样就形成了死锁。预防这种情况发生的方法是在for update of ename 之后指定NOWAIT选项,这样的话,当第二个cursor不会一直等待下去,而是出现ORA-00054 [resource busy and acquire with NOWAIT specified]的
讯息。
4.既然for update of后面的字段是随便那个字段都可以,那么可不可以不写呢?如果你没必要指定NOWAIT选项,那么后面的字段就可以不写;如果你必须指定NOWAIT选项,则必须指定至少一个字段。
5.还有一种方法是用ROWID替代WHERE CURRENT OF YOUR_CURSOR_NAME语句。
如下代码:
declare
-- query emp.name
cursor cur_emp
is
select a.deptno,
a.dname,
a.rowid,
b.rowid rowid_1
from dept a, emp b
where empno = 7369
and a.deptno = b.deptno
for update nowait;
-- local variables
v_deptno dept.deptno%type;
v_dname dept.dname%type;
v_rowid rowid;
v_rowid_1 rowid;
begin
open cur_emp;
loop
fetch cur_emp into v_deptno, v_dname, v_rowid, v_rowid_1;
exit when cur_emp%notfound;
update dept
set dname = 'abc'
where rowid = v_rowid;
update emp
set ename = 'frank'
where rowid = v_rowid_1;
end loop;
close cur_emp;
commit;
exception
when others then
rollback;
raise;
end;
由此,推荐的for update的习惯是:
NOWAIT定然跟FOR UPDATE之后。
直接用ROWID替代WHERE CURRENT OF YOUR_CURSOR_NAME语句,
尤其在相对繁习的程序里头。
COMMIT必需存在程序结尾。以防死锁成形。
EXCEPTION里的ROLLBACK是最基本的需要。