11

当我使用FOR UPDATE OF SAL或简单地编写FOR UPDATE.

根据奥莱利

FOR UPDATE 子句的 OF 列表不限制您仅更改列出的那些列。锁仍然放置在所有行上;OF 列表只是为您提供了一种更清楚地记录您打算更改的内容的方法。如果您只是在查询中声明 FOR UPDATE 并且在 OF 关键字之后不包含一或多个列,那么数据库将锁定 FROM 子句中列出的所有表中所有已识别的行。

这意味着,当我用 指定列名时FOR UPDATE OF SAL,其他用户只能用SAL列进行更改。但是,实际上,情况并非如此。我仍然在其他会话中被锁定。谁能解释一下区别。

更新

 ----- SESSION 1

declare
 emp_info emp.ename%type;
 cursor emp_cur is select ename from emp join dept using(deptno) where deptno=&no for update of sal;
 begin
 open emp_cur;
 loop
 fetch emp_cur into emp_info;
 exit when emp_cur%notfound;
 dbms_output.put_line(emp_info);
 end loop;
 close emp_cur;
 end;

  ----- SESSION 2

  update emp set comm=5 where deptno=10;
  ---- hanged/waiting in session 2
4

2 回答 2

19

Oracle 文档

使用OF ...column 子句仅锁定连接中特定表或视图的选择行。OF子句中的列仅指示哪些表或视图行被锁定。您指定的特定列不重要。但是,您必须指定实际的列名,而不是列别名。如果省略此子句,则数据库将锁定查询中所有表中的选定行。

FOR UPDATE如果您的查询引用单个表,则和之间没有区别FOR UPDATE OF ...,但后者可能仍可用作自文档以指示您打算更新哪些列。它不限制您可以更新的内容。如果你有:

CURSOR cur IS SELECT * FROM emp FOR UPDATE OF sal;

那么你仍然可以这样做:

UPDATE emp SET comm = comm * 1.1 WHERE CURRENT OF cur;

但是,如果有多个表,则只会锁定包含您在子句FOR UPDATE OF ...中指定的列的表中的行。OF

与我认为您在问题中所说的相反。指定FOR UPDATE OF sal不仅锁定sal列;您永远不能锁定单个列,最小锁定在行级别。(阅读更多关于锁的信息)。它锁定表中包含SAL由查询选择的列的所有行。


在对您的问题的更新中,您的游标查询正在加入empdept,但该OF子句只有sal, 表中的一列emp。打开游标时,表中的行将被锁定,并且在您或该会话emp之前不会释放这些锁定。在光标循环中,您可以执行以下操作:commitrollback

UPDATE emp SET ... WHERE CURRENT OF emp_cur;

...更新emp表中与此循环迭代相关的行。你不能这样做:

UPDATE dept SET ... WHERE CURRENT OF emp_cur;

...因为dept表中的行未锁定,因为OF. 这也意味着在您的第二个会话中,这些dept行可以自由更新,因为它们没有被第一个会话锁定。

于 2013-04-18T11:30:35.540 回答
0

关于更新的另一条评论。如果您从多个表中选择并且没有 where 子句来引用每个表以进行更新,那么它将锁定所有表,直到更新完成。

于 2013-04-18T16:49:49.273 回答