`
wang4674890
  • 浏览: 87542 次
  • 性别: Icon_minigender_2
  • 来自: 厦门
社区版块
存档分类
最新评论

Oracle 悲观锁和乐观锁

 
阅读更多

一.丢失更新
   
所有多用户环境中存在丢失更新,丢失更新可以如下示例:
   

        发生这种情况的原因:应用开发人员编写的程序时是这样的:更新一个特定的字段时,该记录的所有字段都会“刷新”(只是因为更新所有列更容易,这样就不用先得出哪些列已经修改,并且只更新那些修改过的列)。

       避免这种情况可以用两种锁定策略:悲观锁定或乐观锁定。

二.悲观锁
     
悲观锁定只用于有状态或有连接环境
     在试图更新之前,从数据库查询这一行就锁定这一行。
(因为我们很悲观,对于这一行能不能保持未改变很是怀疑)
  
  select empno,ename,sal from scott.emp where deptno=10;
  

EMPNO  ENAME   SAL
    7782    CLARK    2450.00
    7839    KING       5000.00
    7934    MILLER    1300.00


  在SQLplus中模拟应用可能执行的绑定调用,可以利用下面命名:
 SQL> variable empno number
SQL> variable ename varchar2(20)
SQL> variable sal number
SQL> exec :empno :=7934; :ename :='MILLER'; :sal :=1300;
 
PL/SQL procedure successfully completed


 for update 锁定这一行
 
The FOR UPDATE clause lets you lock the selected rows so that other users cannot lock or update the rows until you end your transaction. You can specify this clause only in a top-level SELECT statement, not in subqueries.
 
锁定命令:
 SQL>  select empno,ename,sal from scott.emp
  2  where empno=:empno and ename=:ename and sal=:sal
  3  for update nowait;

EMPNO ENAME            SAL
----- ---------- ---------
 7934 MILLER       1300.00

试图对这行进行修改
SQL>update scott.emp set ename='ML' where empno=7934;
进程耗在这,因为这行被你锁定了,在你结束你的事务之前,不能修改


查询锁定对象:
SELECT Do.Object_Name, Session_Id, Process, Locked_Mode
FROM V$locked_Object  Lo, Dba_Objects Do
WHERE Lo.Object_Id = Do.Object_Id;

OBJECT_NAM SESSION_ID PROCESS      LOCKED_MODE
  ----------            ----------            ------------           -----------
    EMP                 140                   3204:3008              3

提交事务,锁释放。之后可以进行更新


三.乐观锁
    乐观锁:把所有锁定都延迟到即将执行更新之前才做。换句话说,我们会修改信息而不需要锁。
  
(我们很乐观,认为数据不会被其他用户修改,因此,会等到最后一刻才去看想法对不对)

   实现乐观并发控制的有很多种;
(1)可以在应用中同时保留旧值和新值,然后再更新数据时使用如下语句,这是乐观锁的一种流行实现:
    update table
       set column1 =:new_column1, column2 =:new column2,...
    where primary_key=:primary_key
    and column1 =:old_column1
    and column2 =:old_column2
    ........
 
 
  (2)使用一个特殊的列记录的"版本",这个列由数据库触发器或应用程序代码维护。
 例子: (先建一个表,然后插入数据,在更新时如果实现乐观锁)
 create table carleena.dept
( deptno number(2),
  dname  varchar2(14),
  loc    varchar2(13),
  last_mod timestamp with time zone default systimestamp not null,
  constraint dept_pk primary key(deptno) 
)


插入数据
  insert into carleena.dept(deptno,dname,loc)
  select deptno,dname,loc
  from scott.dept;


进行相关变量的绑定
SQL> variable deptno number;
SQL> variable dname varchar2(14);
SQL> variable loc varchar2(13);
SQL> variable last_mod varchar2(50);
SQL> begin
  2    :deptno :=10;
  3   select dname,loc,last_mod
  4   into :dname,:loc,:last_mod
  5    from carleena.dept
  6  where deptno=:deptno;
  7  end;
  8  /
 PL/SQL procedure successfully completed


deptno    dname                loc              last_mod
  ----------    ----------            ---------              ---------- 
  10          ACCOUNTING  NEW YORK   06-3月 -10 08.55.35.609000 下午 +08:00

执行更新(最后一行执行一个非常重要的检查,以确保时间戳一样,last_mod值一样说明没有进行修改,可以更新)
  SQL> update carleena.dept
  2  set dname = 'AC',
  3  last_mod =systimestamp
  4  where deptno =:deptno
  5  and last_mod =to_timestamp_tz(:last_mod);
 
 1 row updated

执行上面相同逻辑的更新,但是last_mod仍然使用原来绑定的值,没有获取新的值,这时最后一行的值不匹配,故不能进行更新。
  SQL> update carleena.dept
  2  set dname = 'AC1',
  3  last_mod =systimestamp
  4  where deptno =:deptno
  5  and last_mod =to_timestamp_tz(:last_mod);

  0 rows updated

乐观锁定还有其他实现方法


四. 总结:


    注意:两个T1并不是指同一时刻,两个T2也一样不是指同一时刻。
   只是表示一个时间序列

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics