zoukankan      html  css  js  c++  java
  • 锁和闩

    锁(lock)用于管理对共享资源的并发访问。

    在必要时才提交,不要提前。

    锁的问题:

    1.丢失更新

    session1 session2
    (1)查询一行数据 (2)查询同一行数据
    (3)update该行并提交  
      (4)update该行并提交
    这个过程被称为丢失更新 因为(3)所做的所有修改都会丢失

    2.锁定策略:悲观锁(pessimistic)乐观锁(optimistic)

    悲观锁
    这种方式在用户修改数值之前就开始生效了
    乐观锁
    所有锁定动作都延迟到即将执行更新之前才进行
         实现方法:使用版本列的乐观锁,使用用户总和校验的乐观锁

    3.阻塞

    阻塞的Insert
         带主键或唯一约束
         引用完整性约束
    阻塞的Merger、update和delete

    4.死锁

    5.锁升级

    锁的类型

    DML锁
          select、insert、update、merge、delete
          可能是行级锁也可能是表级锁
       1.TX锁
          事务发起第一个修改时会得到TX锁
          Oracle没有使用锁管理器,Oracle锁定过程如下:
             (1)找到想锁定的那一行地址
             (2)到达那一行
             (3)就地锁住这一行,就在行的位置上(如果这一行已经被锁住,就等待锁住他的事务结束,除非指定nowait)

       2.TM(DML Enqueue)锁

          TM锁用于确保在修改表内容时,表结构不会被改变。例如,你已经更新了一个表中的行,那同时也会得到这个表上的一个TM锁。这会防止另一个用户在该表上执行DROP或ALTER命令。如果你有一个TM锁,另一个用户试图在这个表上执行DDL,他就会得到以下错误消息:

    SQL> update EMPLOYEE set comm=200 where EMPNO=7844;

    1 row updated.

     
      SQL> drop table EMPLOYEE;
    drop table EMPLOYEE
               *
    ERROR at line 1:
    ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired

    在11gR2以及更高版本中,可以设置DDL_lock_timeout让DDL等待

    SQL> alter session set DDL_lock_timeout=10;

    Session altered.

    DDL锁
          create和alter语句等,可以保护对象结构定义

          有以下3种类型的DDL锁

          排他DDL锁(exclusive DDL lock)

                防止其他会话得到他们自己的DDL锁或TM(DML)锁。这说明,在DDL期间可以查询一个表,但无法以任何方式修改这个表。

                例如:alter tale t move;

          共享DDL锁(share DDL lock)

                这些锁会保护所引用的对象的结构,使之不会被其他会话修改,但是允许修改数据。

                例如:create index t_idx on t(x) online;

          可中断解析锁(breakable parse lock)

    内部锁0159BD8B和闩latch
          保护内部数据结构

    TX锁实验:

    SQL> create table dept
      2  as select * from scott.dept;

    Table created.

    SQL> create table emp
      2  as select * from scott.emp;

    Table created.
    SQL> alter table dept
      2  add constraint dept_pk
      3  primary key(deptno);

    Table altered.
    SQL> alter table emp
      2  add constraint emp_pk
      3  primary key(empno);

    Table altered.

    SQL> alter table emp
      2  add constraint emp_fk_dept
      3  foreign key(deptno)
      4  references dept(deptno);

    Table altered.

    SQL> create index emp_deptno_idx
      2  on emp(deptno);

    Index created.

    启动一个事务:

    SQL> update dept
      2  set dname=initcap(dname);

    4 rows updated.

    查看:

    SELECT username,
           v$lock.sid,
           TRUNC (id1 / POWER (2, 16)) rbs,
           BITAND (id1, TO_NUMBER ('ffff', 'xxxx')) + 0 slot,
           id2 seq,
           lmode,
           request
      FROM v$lock, v$session
    WHERE     v$lock.TYPE = 'TX'
           AND v$lock.sid = v$session.sid
           AND v$session.username = USER;

    USERNAME                  SID        RBS       SLOT        SEQ    LMODE     REQUEST
    --------------------------- ---------- ---------- ---------- ---------- ---------- ----------
    EODA                               341       7         17        158        6           0

    SQL> select XIDUSN,XIDSLOT,XIDSQN from v$transaction;

    XIDUSN  XIDSLOT XIDSQN
    ---------- ---------- ----------
             7       17         158
    这里有几点很有意思

    v$lock表的LMODE为6,REQUEST为0.查看Oracle Database Reference得到LMODE=6是一个排他锁。请求REQUEST=0则意味着你没有发出请求,也就是说你拥有这个锁。

    这个v$lock表只有一行。Oracle不会在任何地方存储行级锁的列表。要查看某一行是否锁定,必须直接找到这一行。

    RBS、SLOT和SEQ值与v$transaction匹配,这就是我的事务ID

    开启另外一个会话

    SQL> update emp set ename=upper(ename);

    14 rows updated.

    SQL> update dept set deptno=deptno-10;


    现在这个会话被阻塞
    回到原来会话

    SELECT username,
           v$lock.sid,
           TRUNC (id1 / POWER (2, 16)) rbs,
           BITAND (id1, TO_NUMBER ('ffff', 'xxxx')) + 0 slot,
           id2 seq,
           lmode,
           request
      FROM v$lock, v$session
    WHERE     v$lock.TYPE = 'TX'
           AND v$lock.sid = v$session.sid
    11         AND v$session.username = USER;

    USERNAME         SID        RBS       SLOT      SEQ      LMODE     REQUEST
    ------------------- ---------- ---------- ---------- ---------- ---------- ----------
    EODA                      311      10          3       7727        6           0
    EODA                      311       7         17        158        0           6
    EODA                      341       7         17        158        6           0

    SQL> select XIDUSN,XIDSLOT,XIDSQN from v$transaction;

        XIDUSN    XIDSLOT      XIDSQN
    ---------- ---------- ----------
        10        3        7727
         7       17         158
    可以看到开始了一个新事务,事务ID是(10,3,7727),这一次,这个新会话(SID=311)在v$lock有两行。其中一行表示他拥有的锁(LMODE=6)。另外还有一行,显示了一个值为6的REQUEST。这是一个队排他锁的请求。有意思的是,这个请求行的RBS/SLOT/SEQ的值正是锁持有者的事务ID。SID=341的事务阻塞了sid=311的事务。从v$lock的自连查询可以看出:

    SELECT (SELECT username
              FROM v$session
             WHERE sid = a.sid)
              blocker,
           a.sid,
           ' is blocking ',
           (SELECT username
              FROM v$session
             WHERE sid = b.sid)
              blockee,
           b.sid
      FROM v$lock a, v$lock b
    13   WHERE a.BLOCK = 1 AND b.REQUEST > 0 AND a.ID1 = b.ID1 AND a.id2 = b.id2;

    BLOCKER                   SID 'ISBLOCKING'    BLOCKEE                   SID
    ------------------------------ ---------- ------------- ------------------------------ ----------
    EODA                      341  is blocking    EODA                      311
    现在,提交原来的事务(SID=341),再次查询,可以看到请求行不见了

    SQL> commit;

    Commit complete.

    SELECT username,
           v$lock.sid,
           TRUNC (id1 / POWER (2, 16)) rbs,
           BITAND (id1, TO_NUMBER ('ffff', 'xxxx')) + 0 slot,
           id2 seq,
           lmode,
           request
      FROM v$lock, v$session
    WHERE     v$lock.TYPE = 'TX'
           AND v$lock.sid = v$session.sid
    11         AND v$session.username = USER;

    USERNAME                  SID     RBS       SLOT        SEQ    LMODE     REQUEST
    ------------------------------ ---------- ---------- ---------- ---------- ---------- ----------
    EODA                      311      10          3       7727        6           0

    再另外一个会话也可以看到更新完成,结束了被阻塞状态。

    SQL> update emp set ename=upper(ename);

    14 rows updated.

    SQL> update dept set deptno=deptno-10;

    4 rows updated.

    TM锁实验:

    oracle@test1: /home/oracle> sqlplus eoda/foo

    SQL*Plus: Release 11.2.0.4.0 Production on Mon Dec 19 17:25:16 2016

    Copyright (c) 1982, 2013, Oracle.  All rights reserved.


    Connected to:
    Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
    With the Partitioning, OLAP, Data Mining and Real Application Testing options

    SQL> create table t1(x int);

    Table created.

    SQL> create table t2(x int);

    Table created.

    SQL> insert into t1 values(1);

    1 row created.

    SQL> insert into t2 values(1);

    1 row created.

    SELECT (SELECT USERNAME
              FROM v$session
             WHERE sid = v$lock.sid)
              username,
           sid,
           id1,
           id2,
           lmode,
           request,
           block,
           v$lock.TYPE
      FROM v$lock
     13   WHERE sid = SYS_CONTEXT ('userenv', 'sid');

    USERNAME               SID           ID1     ID2    LMODE    REQUEST       BLOCK TY
    ----------------------------- ---------- ---------- ---------- ---------- ---------- ---------- --
    EODA                      331          100        0      4        0           0 AE
    EODA                      331       19824        0      3        0           0 TM
    EODA                      331       19825        0      3        0           0 TM
    EODA                      331     655373    9271      6        0           0 TX


    SQL> col OBJECT_NAME format a20
    select object_name ,object_id
    from user_objects
      3  where object_id in(19824,19825);

    OBJECT_NAME          OBJECT_ID
    -------------------- ----------
    T1              19824
    T2              19825

    尽管每个事物只得到一个TX锁,但TM锁不同,修改了多少个对象,就能得到多少个TM锁。

  • 相关阅读:
    Drawable、Bitmap、byte[]之间的转换
    关于java.lang.IllegalArgumentException: View not attached to window manager 错误的分析
    Android ListView使用BaseAdapter与ListView的优化
    Ubuntu, using svn from terminal
    Ubuntu 12.04(64位)上搭建android 开发环境 (ADT 、android-studio)
    Widget改变大小
    android4.0中实现AppWidget集合
    android 中 AppWidget 的 ListView 的实现
    解决IllegalStateException: Can not perform this action after onSaveInstanceState
    Drawable和Bitmap转换
  • 原文地址:https://www.cnblogs.com/guilingyang/p/6184409.html
Copyright © 2011-2022 走看看