Oracle谨慎使用嵌套查询做为锁机制条件

案例:Oracle 11g里写了一个存储过程,内容为执行update语句,更改表记录状态,目的是对表记录进行锁定。应用服务器集群调用同一个数据库的这个存储过程。最后发现,多个WebLogic实例都更新了同一条记录。锁机制失效。sql

进行代码测试:数据库

数据初始化准备服务器

create table tb_test_tab(
id number(10),
name varchar2(10),
statu varchar2(10)
);

truncate table tb_test_tab;
insert into tb_test_tab values (1001,'1','1');
insert into tb_test_tab values (1002,'2','1');
insert into tb_test_tab values (1003,'3','1');
insert into tb_test_tab values (1004,'4','1');
insert into tb_test_tab values (1005,'5','1');
insert into tb_test_tab values (1006,'6','1');
commit;

在plsql客户端开2个sql窗口,第一个窗口执行如下语句,不进行提交事务。测试

update  tb_test_tab t set t.name='343333',t.statu='2' where t.statu='1' and t.id=1001;

第二个窗口同时执行如下语句,提交事务。spa

update  tb_test_tab t set t.name='343333',t.statu='3' where t.statu='1' and t.id=1001;
commit;

此时第二个语句的commit处于等待状态,如今提交第一个窗口的事务,第二个事务也会当即提交。查看结果发现 t.id=1001记录的 t.statu值为2。说明表的锁机制成功!code

如今换成嵌套语句做为更新条件进行执行更新处理,看下锁机制如何,操做步骤以下:事务

先初始化数据。it

truncate table tb_test_tab;
insert into tb_test_tab values (1001,'1','1');
insert into tb_test_tab values (1002,'2','1');
insert into tb_test_tab values (1003,'3','1');
insert into tb_test_tab values (1004,'4','1');
insert into tb_test_tab values (1005,'5','1');
insert into tb_test_tab values (1006,'6','1');
commit;

一样在plsql客户端开2个sql窗口,第一个窗口执行如下语句,不进行提交事务。语句含义就是将statu='1'的记录升序后的前三条设置statu='2',name='22222'。table

update tb_test_tab t
   set t.name = '22222', t.statu = '2'
 where t.id in (select id
                  from (select r.id from tb_test_tab r where r.statu='1' order by r.id)
                 where rownum <= 3);

第二个窗口同时执行如下语句,提交事务。class

update tb_test_tab t
   set t.name = '33333', t.statu = '3'
 where t.id in (select id
                  from (select r.id from tb_test_tab r where r.statu='1' order by r.id)
                 where rownum <= 3);
commit;

此时第二个语句的commit处于等待状态,如今提交第一个窗口的事务,第二个事务也会当即提交。查看结果发现id升序后的前三条记录的 statu='3',name='33333'。 说明表的锁机制存在异常,至少不是以前咱们想象的那样的结果(以前想象的结果应该是 statu='2',name='22222'。 第二个窗口执行的语句更新记录为0条)!  这个也许就是Oracle内部锁机制灵敏度不针对嵌套语句里面的结果集。故须要谨慎使用嵌套语句做为锁机制的限制条件。

若是想上面嵌套语句不变,同时想让锁机制起到效果,能够将嵌套语句里面的限制条件在最外层再写一遍便可。具体以下。第一个窗口改为:

update tb_test_tab t
   set t.name = '22222', t.statu = '2'
 where t.id in (select id
                  from (select r.id from tb_test_tab r where r.statu='1' order by r.id)
                 where rownum <= 3)
    and t.statu='1';

第二个窗口改为:

update tb_test_tab t
   set t.name = '33333', t.statu = '3'
 where t.id in (select id
                  from (select r.id from tb_test_tab r where r.statu='1' order by r.id)
                 where rownum <= 3)
    and t.statu='1';
commit;

相关文章
相关标签/搜索