for update 和 for update nowait 的区别

数据库 0 685
小小草
小小草 2020年8月14日 07:37 发表
摘要:如果在select语句后加入了for update, 则Oracle一旦发现(符合查询条件的)这批数据正在被修改,则不会发出该select语句查询,直到数据被修改结束(被commit),马上自动执行这个select语句。

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的检查。


点赞 0 收藏(0)    分享
相关标签: 数据库
问题没解决?让chatGPT帮你作答 智能助手
0 个评论
  • 消灭零评论