zoukankan      html  css  js  c++  java
  • Mysql中的表锁和行锁

    Mysql为了解决事物并发执行导致的一些列为题,引入了锁,在InnoDB存储引擎中,锁分为表锁行锁两类。

    1. 共享锁和独占锁(S和X)

    1.1 共享锁(S锁)

    共享锁也叫S锁,S锁与S锁是兼容关系,不会被阻塞,S锁与X锁是不兼容的,会被阻塞。

    加S锁读取数据:

    SELECT ... LOCK IN SHARED MODE;
    

    当在读取到的记录上加S锁,此时允许其他事物继续获取这些记录的S锁,但是不能获取X锁,会被阻塞,直到记录的S锁被释放为止。

    1.2 独占锁(X锁)

    独占锁也叫X锁,X锁和X锁是不兼容的,会被阻塞;X锁与S锁也是不兼容的,会被阻塞。

    加S锁读取数据:

    SELECT ... FOR UPDATE;
    

    会为读取到的记录加X锁,此时不允许其他事务获取这些数据的S锁和X锁。如果其他事物想获取这些记录的S锁或X锁,会被阻塞,直到记录的X锁释放为止。

    其实对于写操作来锁,基本是上都是加的X锁,例如UPDATEDELETE

    DELETE在进行数据删除时,会先获取对应记录的X锁,然后执行删除操作,

    UPDATE在进行数据修改时,在没有修改记录的主键的情况下,也是会先定位到对应的记录,然后获取记录的X锁,然后执行数据更新操作(这里的更新操作可能是将记录放到删除链上,再插入一条新记录;也可能是对修改列的数据进行修改。当被修改的列占用的存储空间发生变化时,前者的情况会发生);如果修改了主键,就会执行DELETE和INSERT操作。

    INSERT进行数据插入时,一般是不会创建任何锁结构的,如果发生事物并发执行冲突时,会创建隐式锁进行处理。

    2. 表锁

    大概有以下几种:

    1. 表级S锁和X锁,分别表示表级别的共享锁和独占锁
    2. 表级意向锁,分为IS意向共享锁和IX意向独占锁
    3. 自增锁,还可以再分为两种锁
      1. AUTO-INC锁,在insert语句执行完成后会释放锁
      2. 轻量级锁,在生成值后会释放锁

    2.1 表级S锁和X锁

    一般是用不到表级S锁和X锁的,当然我们也可以手动获取表级S锁和X锁。

    这里的READ对应的就是S锁,WRITE对应的是X锁。

    LOCK TABLES 表名 READ;
    LOCK TABLES 表名 WRITE;
    

    2.2 意向锁

    意向锁主要是用来表示一个加锁的状态的,目的是当其他事物加表锁的时候,可以快速知道当前表中有没有记录被加锁了。比如向表中的一条记录加S锁时,会先在表级别加一个IS锁,然后对记录加S锁。当下一个事务过来加表锁的时候,就可以通过判断表是否意向锁来确定表中是否有记录被加锁,从而避免了每次在加表锁的时候还要去遍历每条记录看是否加锁了。

    2.3 自增锁

    AUTO_INCREMENT修饰的列执行插入操作时,会使用自增锁,生成对应的列的值,然后将数据插入到表中。自增锁主要分为以下两种:

    1. AUTO-INC锁,在执行插入语句时,会加一个表级别的锁,然后为对应的列生成值,最后插入数据并释放自增锁。一般在无法预计插入数据条数时,会使用该方式进行自增列的值生成。
    2. 轻量级锁,在执行插入语句时,会获取自增锁,生成对应的列的值,然后释放锁,最后插入数据。一般在确定插入数据条数时,会使用该方法进行自增列值的生成。

    3. 行级锁

    行级锁是用来给表中的记录进行加锁的,与表级锁相比,锁的粒度更细,能提供更好的并发性能,但是会占用更多的资源。

    3.1 记录锁(LOCK_REC_NOT_GAP)

    记录锁锁定的是一条记录,有S锁和X锁之分,如果是给一条记录加了X记录锁,那么其他事物将无法获取该记录的X记录锁和S记录锁;如果给一条记录加了S记录锁,那么其他事物只能对该记录加S记录锁,不能加X记录锁。

       锁定id为5的这条记录加LOCK_REC_NOT_GAP
               ^
               |
               |
     _______________
    | 1 | 3 | 5 | 8 |
    |---------------|
    | c | d | a | b | 
     ---------------
    

    3.2 间隙锁(LOCK_GAP)

    间隙锁锁定的是两个相邻记录中间的间隙,目的是锁定相邻记录的间隙,方式数据插入,Mysql中正是使用了这种方式进行加锁防止幻影行的插入。如下图所示,给ID为5的数据加间隙锁,会锁定ID为5的记录前面的间隙。间隙锁也分S锁和X锁,但是间隙锁的S锁和X锁的效果是一样的。

    LOCK_GAP只是为了防止幻影行的插入,所以加了间隙锁,并不影响其他事物为该记录加记录锁和间隙锁。

     锁定id为5的这条记录加LOCK_GAP
             ^
             |
             |
     _______________
    | 1 | 3 | 5 | 8 |
    |---------------|
    | c | d | a | b | 
     ---------------
    

    3.3 Next-Key锁(LOCK_ORDINARY)

    Next-Key锁可以看作是记录锁和间隙锁的合体,Next-Key锁会锁定记录前面的间隙和该记录

     锁定id为5的这条记录加LOCK_ORDINARY
             ^ ^
             | |
             | |
     _______________
    | 1 | 3 | 5 | 8 |
    |---------------|
    | c | d | a | b | 
     ---------------
    

    3.3 意向插入锁(LOCK_INSERT_INTENTION)

    当记录插入时,要入位置被其他事物加了间隙锁(Next-Key锁也包含间隙锁),插入操作的事物会生成一个插入意向锁,然后进入等待状态等待间隙锁释放。

    3.4 隐式锁

    当一个事物进行记录插入操作,本身插入操作是不会创建任何锁结构的,但是此时遇到了另外一个事物在需要对该记录进行加锁(X锁或者S锁),此时就可能会出现脏读/写的情况,因为插入操作本身没有进行任何加锁,如果此时插入操作的事物没有提交,第二个事务如果锁定了该记录,进行了读或者写操作,就会出现脏读/写。

    如果想避免脏读/写,正确的操作应该是先判断插入操作的事务是否提交了,如果提交了第二个事务就可能正常读/写该记录,如果没有提交,第二个事务就需要进入等待状态,此时第二个事务就会为插入操作的事物创建一个X锁,为当前事物本身(第二个事务)也创建一个锁结构,然后进入等待状态,此时第一个事物还在执行,第二个事务进入了阻塞状态,两个事物都对应一个锁结构。

    4. 锁结构

    • 锁所在的事物信息 指向事物信息的指针
    • 索引信息 记录行级锁加锁的索引
    • 表/行锁信息
      • 表锁信息
      • 行锁信息
        • Space ID 记录所在的表空间
        • Page Number 记录所在的页号
        • n_bits 表示使用了多少个尾部的bit位
    • type_mode 记录的是锁相关的信息还有等待状态
      • lock_mode 锁模式,占用低4位
        • LOCK_IS 共享意向锁
        • LOCK_IX 独占意向锁
        • LOCK_S 共享锁
        • LOCK_X 独占锁
        • LOCK_AUTO_INC AUTO-INC锁
      • lock_type 锁类型
        • LOCK_TABLE 表锁
        • LOCK_REC 记录锁
      • rec_lock_type 行锁的具体类型
        • LOCK_ORDINARY next-key锁
        • LOCK_GAP 间隙锁
        • LOCK_REC_NOT_GAP 记录锁
        • LOCK_INSERT_INTENTION 意向锁
        • 其他信息
        • LOCK_WAIT 等待状态
    • 其他信息
    • 一堆bit位 如果是行锁,每一个bit位对应一条记录,0表示对应的记录没有加锁,1表示对应记录加锁了
            _________________  
           | 锁所在的事物信息  |
           |----------------|
           |     索引信息     |
           |----------------|
           |  表/行锁信息     |
           |----------------|
           |   type mod     |
           |--------------—-|
           |   其他信息      |
           |----------------|
           |   一些bit位     |
            ---------------- 
    
    GitHub:https://github.com/godfunc
    博客园:http://www.cnblogs.com/godfunc
    Copyright ©2019 Godfunc
  • 相关阅读:
    JAVA---JDK环境变量的配置
    “==” 与“equals(Object)”区别
    js替换字符串中所有斜杠
    uploadify学习笔记
    VBA学习笔记
    浮动导航条的实现
    canvas初识笔记
    EntityFramework存储过程的返回类型
    CSS及html的特殊字符表
    DIV六种实现元素水平居中
  • 原文地址:https://www.cnblogs.com/Godfunc/p/15240448.html
Copyright © 2011-2022 走看看