【MySQL】锁入门

要作的彻底掌握MySQL/InnoDB的加锁规则,甚至是其余任何数据库的加锁规则,须要具有如下的一些知识点数据库

  1. 了解数据库的一些基本理论知识:数据的存储格式 (堆组织表 vs 聚簇索引表);并发控制协议 (MVCC vs Lock-Based CC);Two-Phase Locking;数据库的隔离级别定义 (Isolation Level);
  2. 了解SQL自己的执行计划 (主键扫描 vs 惟一键扫描 vs 范围扫描 vs 全表扫描);
  3. 了解数据库自己的一些实现细节 (过滤条件提取;Index Condition Pushdown;Semi-Consistent Read);
  4. 了解死锁产生的缘由及分析的方法 (加锁顺序不一致;分析每一个SQL的加锁顺序)

有了这些知识点,再加上适当的实战经验,全面掌控MySQL/InnoDB的加锁规则,当不在话下。并发

最近开始关注MySQL的锁问题,也但愿开始对锁有个大概的认识,今天从简单的概念入手;通常分为2种,一种是DML操做时的锁机制,另外一种,则是在DDL操做时,锁是如何来进行控制的。学习

做为学习的开始,仍是先从简单的入手比较合适,因此,这里做为一个入门级的第一篇文章,先简单介绍下DML中涉及到的读写锁,即便如此,也仍是在实际实验中,遇到了和理论不一致的状况,暂时还不能给你们拿出合理解释,下面给出详情:code

  1. 共享锁和排它锁索引

    InnoDB支持最小粒度到数据行的行级锁:事务

    • 共享锁,容许事务经过持有共享锁去读取一行
    • 排他锁,容许事务经过持有排它锁去更新或者删除一行

    一行数据,能够容许多个事务同时持有共享锁,可是只能有一个事务持有排他锁,若是另外一个事务也须要持有排他锁,则须要等待以前持有该锁的事务,释放掉锁get

  2. 意向锁it

    InnoDB除行级锁之外,还在表级别,添加了一种叫作意向锁的概念,其表示事务即将对该表的某些行作读或者写操做io

    • 共享意向锁,表示某事务即将要对该表的某些行数据加共享锁
    • 排它意向锁,表示某事务即将要对该表的某些行数据加排他锁

    举个例子:入门

    select ... lock in share mode 将在表上持有IS共享意向锁,select for update则是在表上持有IX排他意向锁
    

    意向锁的两个使用规约:

    • 事务在持有表上某行数据的行共享锁以前,必须先持有表上的共享意向锁,或者级别更高的排他意向锁
    • 事务在持有表上某行数据的行排他锁以前,必须先持有表上的排他意向锁

    表级别的意向锁和行级别的锁,排斥关系以下:

      X IX S IS
    X Conflict Conflict Conflict Conflict
    IX Conflict Compatible Conflict Compatible
    S Conflict Conflict Compatible Compatible
    IS Conflict Compatible Compatible Compatible

    举一个例子:

    事务A执行了select lock in share mode ,这时,事务A持有了IS锁和S锁(为啥要加上 lock in share mode 呢?不加,就是快照读,不会要求去持有锁,反过来,利用lock in share mode,能够在业务上实现原子读写操做哦,你们能够本身思考一下) 事务B要在相同的行上,执行update 语句,那么这时,事务B首先要去持有表级别的IX锁,根据上图第2行最后一列,IX 和 IS 是共享的,因此,这个没问题。而后,事务B要对相同的行,作写操做,因此其须要持有X锁,根据上图第1行第3列,X和S是不兼容的,因此事务B须要等待事务A结束之后,才能执行。

    • 反思1:若是事务A使用select for update,事务B会如何反映?(结果同样,事务B会等待事务A结束)
    • 反思2:若是事务B,update不一样的行,事务B会如何反映?(结果不同,事务B不须要等待事务A)
    • 反思3:若是根据第一行第三列的规则,岂不是一个事务作了update操做,另外一个事务就不能读了?写阻塞读?(其实读,都是快照读,并不会要求持有S锁)
  3. 行级锁

    行级锁老是针对某个索引记录进行加锁,用以防止其余事物并发对当前加锁的行进行读取和修改。因此,及时用户没有定义任何索引和主键,MySQL也会在内部,自动生成一个隐含的主键列。 行级锁,其目的,就是为了保证多个事务不能同时对相同的一条数据执行修改动做

  4. 间隙锁

    间隙锁,顾名思义,其锁定的是若干个索引记录的某个范围(不包括记录自己),好比:SELECT c1 FROM t WHERE c1 > 10 and c1 < 20 FOR UPDATE; 这个就锁定了10~20的这个范围(10.20),防止其余事物,插入c1的值在10~20直接的记录,但c1等于10或者c1等于20,则是容许被插入的 如上SQL所示,间隙表跟行级锁的一个区别在于,间隙锁是锁定了一个区间范围,防止别人对这个区间内的数据,执行insert或者update。

    小实验:

    假如在索引列上,事务A执行的是 c1 between 10 and 20 for update,那么,事务B可以插入c1等于10(或者20)的记录吗?

  5. Next-Key锁

    接上一个问题,假如事务A执行的是 c1 between 10 and 20 for update,那么,除了锁定10,20的区间之外,还须要锁定记录自己(10和20),这就是Next-Key锁: Next-Key就是间隙锁的一种升级,其锁定的内容,除了范围之外,还包含记录的自己,好比,C1这个普通索引列上,有3条数据:1,10,20,30,那么,可能存在的Next-Key的锁有如下几种(区间 + 记录):(无限小,1]. (1,10]. (10,20] . (20,30]. (30,无限大)

    当执行select * from A where c1 between 10 and 20 for update时,其加上的锁:为:(1,10],(10,20],(20,30),其范围会扩大到当前Key的下一个值中去,你会发现,在事务B中,c1 >1 到C1 < 30 的记录,所有不容许插入,而不只仅是10到20直接。

  6. 自增锁

    表级别,还有一个特殊的锁:自增锁,后面的文章,将给出详细介绍。

参考: MySQL 加锁处理分析

相关文章
相关标签/搜索