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锁。

  • 相关阅读:
    LeetCode 123. Best Time to Buy and Sell Stock III (stock problem)
    精帖转载(关于stock problem)
    LeetCode 122. Best Time to Buy and Sell Stock II (stock problem)
    LeetCode 121. Best Time to Buy and Sell Stock (stock problem)
    LeetCode 120. Triangle
    基于docker 搭建Elasticsearch5.6.4 分布式集群
    从零开始构建一个centos+jdk7+tomcat7的docker镜像文件
    Harbor实现容器镜像仓库的管理和运维
    docker中制作自己的JDK+tomcat镜像
    docker镜像制作---jdk7+tomcat7基础镜像
  • 原文地址:https://www.cnblogs.com/guilingyang/p/6184409.html
Copyright © 2011-2022 走看看