您的位置:首页 > 数据库 > Oracle

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

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

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

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

悲观锁的实现:
SQL> variable empno number
SQL> variable ename
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.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: