for update 和 for update nowait 的区别

for update 和 for update nowait 的区别

如果在select语句后加入了for update Oracle一旦发现(符合查询条件的)这批数据正在被修改,则不会发出该select语句查询,直到数据被修改结束(被commit),马上自动执行这个select语句。           

 同样,如果该查询语句发出后,有人需要修改这批数据(中的一条或几条),它也必须等到查询结束后(commit)后,才能修改。          

for update nowait for update 都会对所查询到得结果集进行加锁,所不同的是,如果另外一个线程正在修改结果集中的数据,for update nowait 不会进行资源等待,只要发现结果集中有些数据被加锁,立刻返回 ORA-00054错误,内容是资源正忙, 但指定以 NOWAIT 方式获取资源”。          

for update for update nowait 加上的是一个行级锁,也就是只有符合where条件的数据被加锁。如果仅仅用update语句来更改数据时,可能会因为加不上锁而没有响应地、莫名其妙地等待,但如果在此之前,for  update NOWAIT语句将要更改的数据试探性地加锁,就可以通过立即返回的错误提示而明白其中的道理,或许这就是For UpdateNOWAIT的意义之所在。

for update 和 for update nowait如果对应的select语句有where条件时,只会锁住对应的where条件下的数据,而不会锁住整张表中的所有数据。

在编写程序中,如果涉及到对表进行update,一定要对该表进行锁定,否则将出现死锁情况。

example:

当执行如下语句未进行commit时:SELECT * FROM cux_test t WHERE t.process_status = 'PENDING' FOR UPDATE NOWAIT;

同时再执行对应的如下程序,会报资源正忙的错误:

DECLARE
  CURSOR cur_lock IS
    SELECT *
      FROM cux_test t
     WHERE t.process_status = 'PENDING'
       FOR UPDATE NOWAIT;
BEGIN
  --check lock table
  OPEN cur_lock;
  dbms_output.put_line('IN CURSOR cur_lock');
  IF cur_lock%NOTFOUND THEN
    CLOSE cur_lock;
  END IF;
  CLOSE cur_lock;
 
  --update table
  UPDATE cux_test c
     SET c.process_group_id = 1
   WHERE c.process_status = 'SKIP';
  dbms_output.put_line('update table1 success');
EXCEPTION
  WHEN OTHERS THEN
    dbms_output.put_line('error');
    dbms_output.put_line('other error' || SQLERRM);
END;

而当我们另外执行对应的process_status不是PENDING的for update nowait语句时不会报任何错:

DECLARE
  CURSOR cur_err_lock IS
    SELECT *
      FROM cux_test t
     WHERE t.process_status = 'SKIP'
       FOR UPDATE NOWAIT;
BEGIN
  --check lock table
  OPEN cur_err_lock;
  dbms_output.put_line('IN CURSOR cur_err_lock');
  IF cur_err_lock%NOTFOUND THEN
    CLOSE cur_err_lock;
  END IF;
  CLOSE cur_err_lock;
 
  --update table
  UPDATE cux_test c
     SET c.process_group_id = 2
   WHERE c.process_status = 'SKIP';
  dbms_output.put_line('update table2 success');
EXCEPTION
  WHEN OTHERS THEN
    dbms_output.put_line('error');
    dbms_output.put_line('other error' || SQLERRM);
END;
这里需要注意的是for update和for update nowait语句在同一session中只要使用一次就能锁住对应表的对应记录直到该session结束,意思是在一个session中如果对一张表update多次时只要进行一次lock的检查。

你可能感兴趣的:(Oracle,EBS)