关于oracle锁机制(一悲观锁与乐观锁)

一.悲观锁
当用户想要修改一条数据时,根据键盘上的输入的数据,应用将提供绑定变量的值,然后重新利用这些绑定的变量的值作为过滤条件去查询这一行,这一次会锁定这一行,不允许其他会话更新。
在试图更新前就把记录锁住了,我们很悲观,对于这一行能不能保持未改变很是怀疑。


注意:
       1.如果在查询这条数据和锁这条数据之间,有人做了修改,那么就会得到0行,说明屏幕上的数据是过时的。
       2.如果在查寻这条数据时另一个用户正在更新,那么会得到ORA-00054:resource busy。

应用范围:仅用于有状态或有连接的环境,也就是说你的应用和数据库有一条持续的连接,而且至少再事务生存期中只有你一个人使用这条连接。c/s模式。
   因为根据屏幕的输入应用要反查数据库,看对应的数据有没有变化,没变化就加锁,在对这行的更新提交了后才释放锁,这个过程要求连接是连续的。


悲观锁的实现:
SQL> variable empno number
SQL> variable enam e vachar2(20)
SQL> variable ename varchar2(20)
SQL> variable sal number
SQL> exec :empno :=7934; :ename :='MILLER'; :sal :=1300;
--应用根据屏幕的输入绑定变量(empno,ename,sal)

select empno,ename,sal from emp where empno =:empno and decode(ename,:ename,1)=1 and decode(sal,:sal,1)=1 for update nowait
--反查数据库看相应的数据利用应用最初绑定的变量的值能查到不,如果能查到就给这行数据加锁。
update emp set ename= :ename,sal=:sal where empno=:empno;
commit;
--执行更新,释放锁。
二.乐观锁
乐观锁的实现(使用版本列的乐观锁定):
   一.查询出要更新的字段的值,这里与悲观锁定有两个不同的地方:1.在表里多了一个字段(last_mod用于记录行的版本,如果有更新他业会更新)2.查处记录然后绑定变量但不锁定此行。
SQL> variable deptno number
SQL> variable dname varchar2(14)
SQL> variable loc varchar2(13)
SQL> variable last_mod varchar2(50)
SQL>
SQL> begin
   2   :deptno :=10;
   3   select dname,loc,to_char(last_mod,'DD-MON-YYYY HH.MI.SSXFF AM TZR')
   4       into :dname,:loc,:last_mod
   5   from dept
   6   where deptno =:deptno;
   7   end;
   8   /
二.执行以下语句更新,要是更新一行的话说明在这个会话更新前没有人对此记录进行更新,这里主要靠第4行来验证记录是否被更新;但如果更新了0行,说明在此会话查询出记 录但在修改记录前有会话对此记录做了修改(也利用此逻辑更新的),并将last_mod=systimestamp,所以last_mod =to_timestamp_tz(:last_mod,'DD-MON-YYYY HH.MI.SSXFF AM TZR')条件不满足。
   SQL> update dept
   2   set dname=initcap(:dname),last_mod=systimestamp
   3   where deptno =:deptno
   4     and last_mod =to_timestamp_tz(:last_mod,'DD-MON-YYYY HH.MI.SSXFF AM TZR');
三。但是如果执行更新失败的话,应该怎么办呢。oracle推荐由存储过程来维护last_mod这一字段,更新返回0行时,抛给客户一个异常,让客户知道更新失败了。

乐观锁的实现(使用校验和的乐观锁定ORA_HASH):
   一.查询要修改的行,并且算出这一行的散列值,并绑定在:hash。
SQL>   variable deptno number
SQL> variable dname varchar2(14)
SQL> variable loc varchar2(13)
SQL> variable hash number
SQL> begin
   2   select deptno,dname,loc,
   3   ora_hash(dname || '/' || loc) hash
   4   into :deptno,:dname,:loc,:hash
   5   from dept
   6   where deptno=10;
   7   end;
   8   /
二。更新时检查这一行的散列值更更新之前查询出来的散列值是否一样。
SQL> exec :dname:=lower(:dname);

PL/SQL procedure successfully completed.

SQL> update dept
   2   set dname=:dname
   3   where deptno=:deptno and ora_hash(dname || '/' || loc) =:hash
   4   /

1 row updated.
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值