通常,select ... for update是为了锁定相关的行,保证在查询期间到释放的时候,相关的行集在这个过程中不被其他会话进行写操作(但是其他行集却并无影响)。
比如,有表:
create table t ( id number);
insert into t select object_id from dba_objects where object_id<=100;
commit;
现在t表有100行数据,从1到100;
然后我们在两个会话中进行测试: select ... for update
|
会话A
|
会话A执行结果
|
会话B
|
会话B执行结果
|
|
delete from t where id=2;
|
执行成功。
|
|
|
|
|
|
select * from t for update;
|
会话被挂起。
|
|
commit;
|
提交成功。
|
|
A会话提交后,B会话执行成功。得到结果集。
|
|
update t set id=-1 where id =10;
|
会话被挂起。
|
|
|
|
|
执行成功。
|
commit或rollback(这里实际上并无任何数据更改)。
|
提交成功或回滚成功。
|
这里,我们看到。当某一行被会话A修改或删除锁定时,如果其他会话执行select for update,就会被挂起。直到会话A提交或回滚,释放了锁。
而当某个会话执行了select ... for update 后,其他会话身体在相关的行集进行写操作(更新或删除),也会被挂起,直到该会话解除锁定。其他会话的写操作才能完成。
那么select ... for update nowait 又有什么区别呢?
接下来测试 : select ... for update nowait
|
会话A
|
会话A执行结果
|
会话B
|
会话B执行结果
|
|
delete from t where id=2;
|
执行成功。
|
|
|
|
|
|
select * from t for update nowait;
|
立即返回错误。
第 1 行出现错误:
ORA-00054: 资源正忙, 但指定以 NOWAIT 方式获取资源
|
|
commit;
|
提交成功。
|
|
A会话提交后,B会话执行成功。得到结果集。
|
|
update t set id=-1 where id =10;
|
会话被挂起。
|
|
|
|
|
执行成功。
|
commit或rollback(这里实际上并无任何数据更改)。
|
提交成功或回滚成功。
|
通过两个比的对比发现。当使用 select ... for update 的时候,如果有相关的行被锁定。那么,查询会被挂起,直到其他会话的锁定被解除。使用select ... for update nowait 的时候,如果有相关行被锁定。不再是挂起,是直接返回一个资源忙的错误。
另外,无论是使用select ... fro update 还是使用 select ... fro update nowait。都会对相关的行集进行锁定,其他会话进行相关行集的写操作都会被挂起,直到该锁定被解除。所以,在使用了select ... fro update或者 select ... fro update nowait 后,要尽快解除锁定,避免其他会话挂起太久。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/29802484/viewspace-1270639/
,如需转载,请注明出处,否则将追究法律责任。