zoukankan      html  css  js  c++  java
  • Innodb锁相关总结

    一、InnoDB共有七种类型的锁:
    (1)共享/排它锁(Shared and Exclusive Locks)
    (2)意向锁(Intention Locks)
    (3)插入意向锁(Insert Intention Locks)
    (4)记录锁(Record Locks)
    (5)间隙锁(Gap Locks)
    (6)临键锁(Next-key Locks)
    (7)自增锁(Auto-inc Locks)

    二、共享/排它锁(Shared and Exclusive Locks)

      参考博客:https://blog.csdn.net/u014292162/article/details/83271299
      共享锁(Share Locks,记为S锁),读取数据时加S锁,也叫读锁。
      排他锁(eXclusive Locks,记为X锁),修改数据时加X锁,也叫写锁。
        (1)事务拿到某一行记录的共享S锁,才可以读取这一行;
        (2)事务拿到某一行记录的排它X锁,才可以修改或者删除这一行;
      其兼容互斥表如下:
       S X
        S 兼容 互斥
        X 互斥 互斥
       即:
        (1)共享锁之间不互斥,多个事务可以拿到一把S锁,读读可以并行;
        (2)排他锁与其他任何锁互斥,只有一个事务可以拿到X锁,写写/读写必须互斥;
      因此,一旦写数据的事务没有完成,数据是不能被其他事务读取的,这对并发度有较大的影响。写事务没有提交,读相关数据的select也会被阻塞。  
      MyISAM引擎只有表级的共享锁、排他锁,而Innodb还有行级的共享锁、排他锁。

      由于数据加排他锁后,读相关数据也会被阻塞,因此并发性很低,由此引出了MVCC多版本并发控制:
      参考博客:https://www.cnblogs.com/dongqingswt/p/3460440.html
      数据多版本是一种能够进一步提高并发的方法,它的核心原理是:
        (1)写任务发生时,将数据克隆一份,以版本号区分;
        (2)写任务操作新克隆的数据,直至提交;
        (3)并发读任务可以继续读取旧版本的数据,不至于阻塞;
      MVCC就是通过“读取旧版本数据”来降低并发事务的锁冲突,提高任务的并发度。

    三、意向锁(Intention Locks)

      意向锁是指,未来的某个时刻,事务可能要加共享/排它锁了,先提前声明一个意向。
      意向锁有这样一些特点:
        (1)首先,意向锁,是一个表级别的锁(table-level locking);
        (2)意向锁分为:
          意向共享锁(intention shared lock, IS),它预示着,事务有意向对表中的某些行加共享S锁
          意向排它锁(intention exclusive lock, IX),它预示着,事务有意向对表中的某些行加排它X锁
          举个例子:
            select ... lock in share mode,要设置IS锁;
            select ... for update,要设置IX锁;
        (3)意向锁协议(intention locking protocol)并不复杂:
          事务要获得某些行的S锁,必须先获得表的IS锁
          事务要获得某些行的X锁,必须先获得表的IX锁
        (4)由于意向锁仅仅表明意向,它其实是比较弱的锁,意向锁之间并不相互互斥,而是可以并行,其兼容互斥表如下:
        IS IX
         IS 兼容 兼容
         IX 兼容 兼容
        (5)额,既然意向锁之间都相互兼容,那其意义在哪里呢?它会与表级的共享锁/排它锁互斥,其兼容互斥表如下:
               S X
          IS 兼容 互斥
          IX 互斥 互斥
      意向锁的作用就是:
        当一个事务在需要获取资源的锁定时,如果该资源已经被排他锁占用,则数据库会自动给该事务申请一个该表的意向锁。
        如果自己需要一个共享锁定,就申请一个意向共享锁。如果需要的是某行(或者某些行)的排他锁定,则申请一个意向排他锁。
        注:意向共享锁可以同时并存多个,但是意向排他锁同时只能有一个存在。
      例如下面的例子:
        (1)事务A锁住了表中的一行,让这一行只能读,不能写,即行级S锁。
        (2)之后,事务B申请整个表的写锁,及表级X锁。
      如果没有意向锁,如果事务B申请成功,那么理论上它就能修改表中的任意一行,这与A持有的行锁是冲突的。
      数据库需要避免这种冲突,就是说要让B的申请被阻塞,直到A释放了行锁。
      数据库要怎么判断这个冲突呢?
    step1:判断表是否已被其他事务用表锁锁表
    step2:判断表中的每一行是否已被行锁锁住。
    注意step2中通过遍历查询,这样的判断方法效率实在不高,因为需要遍历整个表。
    于是就有了意向锁。在意向锁存在的情况下,事务A必须先申请表的意向共享锁IS,成功后再申请一行的行锁。
    在意向锁存在的情况下,上面的判断可以改成
    step1:不变
    step2:发现表上有意向共享锁,说明表中有些行被共享行锁锁住了,因此,事务B申请表的写锁会被阻塞。
    最终结论:
    (1)申请意向锁的动作是数据库完成的,就是说,事务A申请一行的行锁的时候,数据库会自动先开始申请表的意向锁,不需要我们程序员使用代码来申请。
    (2)IX,IS是表级锁,不会和行级的X,S锁发生冲突。只会和表级的X,S发生冲突。行级别的X和S按照普通的共享、排他规则即可。
    所以之前的示例中第2步不会冲突,只要写操作不是同一行,就不会发生冲突。
    四、插入意向锁(Insert Intention Locks)

      ---InnoDB并发插入,居然使用意向锁? https://mp.weixin.qq.com/s?__biz=MjM5ODYxMDA5OQ==&mid=2651961461&idx=1&sn=b73293c71d8718256e162be6240797ef&chksm=bd2d0da98a5a84bfe23f0327694dbda2f96677aa91fcfc1c8a5b96c8a6701bccf2995725899a&scene=21#wechat_redirect
      插入意向锁,是间隙锁(Gap Locks)的一种(所以,也是实施在索引上的),它是专门针对insert操作的。
      多个事务,在同一个索引,同一个范围区间插入记录时,如果插入的位置不冲突,不会阻塞彼此。
      例如:在MySQL,InnoDB,RR下:
        t(id unique PK, name);
        数据表中有数据:
          10, shenjian
          20, zhangsan
          30, lisi
        事务A先执行,在10与20两条记录中插入了一行,还未提交:
          insert into t values(11, xxx);
        事务B后执行,也在10与20两条记录中插入了一行:
          insert into t values(12, ooo);
        (1)会使用什么锁?
        (2)事务B会不会被阻塞呢?
        回答:虽然事务隔离级别是RR,虽然是同一个索引,虽然是同一个区间,但插入的记录并不冲突,故这里:
    使用的是插入意向锁
    并不会阻塞事务B

    五、记录锁(Record Locks)

      记录锁即行锁,只有Innodb引擎才有,它封锁索引记录,例如:
        select * from t where id=1 for update;
        它会在id=1的索引记录上加X锁,以阻止其他事务查询、插入,更新,删除id=1的这一行,即与其他任何锁互斥。
        select * from t where id=1 in share mode;
        它会在id=1的索引记录上加S锁,以阻止其他事务插入,更新,删除id=1的这一行,但是其他事务也可以获取该行的S锁,即读读不互斥。
      需要说明的是:
        select * from t where id=1;
      则是快照读(SnapShot Read),它并不加锁,根据MVCC查询。

    六、间隙锁(Gap Locks)

      间隙锁,它封锁索引记录中的间隔,或者第一条索引记录之前的范围,又或者最后一条索引记录之后的范围。
      依然是上面的例子,InnoDB,RR:
        t(id PK, name KEY, sex, flag);
      表中有四条记录:
        1, shenjian, m, A
        3, zhangsan, m, A
        5, lisi, m, A
        9, wangwu, f, B
      这个SQL语句
        select * from t where id between 8 and 15 for update;
      会封锁区间,以阻止其他事务id=10的记录插入。
      画外音:为什么要阻止id=10的记录插入?
        如果能够插入成功,头一个事务执行相同的SQL语句,会发现结果集多出了一条记录,即幻影数据。
        间隙锁的主要目的,就是为了防止其他事务在间隔中插入数据,以导致幻读。
        如果把事务的隔离级别降级为读提交(Read Committed, RC),间隙锁则会自动失效。因为RC隔离级别不能阻止幻读。而RR级别根据间隙锁防止了幻读。

    七、临键锁(Next-key Locks)

      临键锁,是记录锁与间隙锁的组合,它的封锁范围,既包含索引记录,又包含索引区间。
      更具体的,临键锁会封锁索引记录本身,以及索引记录之前的区间。
      如果一个会话占有了索引记录R的共享/排他锁,其他会话不能立刻在R之前的区间插入新的索引记录。
      依然是上面的例子,InnoDB,RR:
        t(id PK, name KEY, sex, flag);
      表中有四条记录:
        1, shenjian, m, A
        3, zhangsan, m, A
        5, lisi, m, A
        9, wangwu, f, B
      PK上潜在的临键锁为:
        (-infinity, 1]
        (1, 3]
        (3, 5]
        (5, 9]
        (9, +infinity]
      执行查询语句:
        select * from t where id between 8 and 15 for update;
      则会在(5,9)和(9, +infinity]加上临建锁,此时如果执行插入语句:
        insert into t values(10, xxx);
      则会阻塞。
      临键锁的主要目的,也是为了避免幻读(Phantom Read)。如果把事务的隔离级别降级为RC,临键锁则也会失效。
      参考:InnoDB,select为啥会阻塞insert? https://mp.weixin.qq.com/s?__biz=MjM5ODYxMDA5OQ==&mid=2651961471&idx=1&sn=da257b4f77ac464d5119b915b409ba9c&chksm=bd2d0da38a5a84b5fc1417667fe123f2fbd2d7610b89ace8e97e3b9f28b794ad147c1290ceea&scene=21#wechat_redirect

    八、自增锁(Auto-inc Locks)  

      参考:插入InnoDB自增列,居然是表锁? https://mp.weixin.qq.com/s?__biz=MjM5ODYxMDA5OQ==&mid=2651961455&idx=1&sn=4c26a836cff889ff749a1756df010e0e&chksm=bd2d0db38a5a84a53db91e97c7be6295185abffa5d7d1e88fd6b8e1abb3716ee9748b88858e2&scene=21#wechat_redirect
      自增锁是一种特殊的表级别锁(table-level lock),专门针对事务插入AUTO_INCREMENT类型的列。
      最简单的情况,如果一个事务正在往表中插入记录,所有其他事务的插入必须等待,以便第一个事务插入的行,是连续的主键值。
      例如:t(id AUTO_INCREMENT, name);,其中id为自增
    
    
  • 相关阅读:
    java.util.concurrent.atomic 包详解
    SpringBoot RESTful 应用中的异常处理小结
    Spring 核心框架体系结构
    Java 的静态代理 动态代理(JDK和cglib)
    Spring5:@Autowired注解、@Resource注解和@Service注解
    offsetWidth/offsetHeight,clientWidth/clientHeight与scrollWidth/scrollHeight的区别
    一个小技能
    在chrome console添加jQuery支持
    如和判断两个浮点数是否相等
    Object.create() vs new SomeFunction() in javascript
  • 原文地址:https://www.cnblogs.com/aiqiqi/p/10512051.html
Copyright © 2011-2022 走看看