MySQL 知识 -- 锁

本文最后更新于:10 分钟前

MySQL 锁

MySQL中有着Lock和Latch的概念,在数据库中,这两者都可以被称为“锁”,但是两者有着截然不同的含义。

  1. Latch一般称为闩锁(轻量级的锁),因为其要求锁定的时间必须非常短。若持续的时间长,则应用的性能会非常差,在InnoDB引擎中,Latch又可以分为 mutex(互斥量)和rwlock(读写锁)。其目的是用来保证并发线程操作临界资源的正确性,并且通常没有死锁检测的机制。

  2. Lock的对象是事务,用来锁定的是数据库中的对象,如表、页、行。并且一般lock的对象仅在事务commit或rollback后进行释放(不同事务隔离级别释放的时间可能不同)。

  • 锁种类

InnoDB 锁

行锁

  1. 共享锁(S): 允许事务读取一行数据

    select * from tableName wherelock in share mode;
  2. 独占锁(X): 允许事务新增或者修改一行数据

    select * from tableName wherefor update;

S 锁和 S 锁之间是可以兼容的,X 锁不能和任何锁兼容

表锁

为了实现多粒度的锁机制,InnoDB 还有两种内部使用的意向锁,由 InnoDB 自动添加,且都是级别的锁。

  1. 意向共享锁(IS): 事务即将给表中的各个行设置共享锁,事务给数据行加 S 锁必须获得该表的 IS 锁

    IS 锁只是不能和 X 锁共存

  2. 意向排他锁(IX): 事务即将给表中的各个行设置排他锁,事务给数据行加 X 锁必须获得该表 IX 锁

    IX 锁不能和 X 和 S 锁共存

意向锁的主要目的是为了使得行锁和表锁共存

InnoDB 存储引擎使用三种行锁的算法用来满足相关事务隔离级别的要求

InnoDB 存储引擎使用三种行锁的算法用来满足相关事务隔离级别的要求

  1. Record Locks (就是行锁)

    索引记录上锁

    如果表中没有定义索引,InnoDB 会默认为该表创建一个隐藏的聚簇索引,并使用该索引锁定记录

  2. Gap Locks

    该锁会锁定一个范围,但是不包括记录本身

    GAP锁的目的,是为了防止同一事务的两次当前读,出现幻读的情况

  3. Next-key Locks

    该锁就是 Record Locks 和 Gap Locks 的组合:即锁定一个范围并且锁定该记录本身

    也就是说,除了锁标识的范围,还会锁住后面的一个 Gap 范围

    InnoDB 使用 Next-key Locks 解决 在 Repeatable read 下的幻读问题

    例如:

    CREATE TABLE `test` ( 
    `id` int(11) primary key auto_increment, 
    `xid` int, KEY `xid` (`xid`) ) 
    ENGINE=InnoDB DEFAULT CHARSET=utf8; 
    insert into test(xid) values (1), (3), (5), (8), (11);

    注意在 xid 上加了索引

    Session A 执行后会锁住的范围:

    (5, 8], (8, 11]

    除了锁住8所在的范围,还会锁住下一个范围,所谓Next-Key

    这样,Session B 执行到第六步会阻塞,第七步也会阻塞,但是并不阻塞第八步,第九步也不阻塞

    上面的结果似乎并不符合预期,因为11这个值看起来就是在 (8, 11] 区间里,而5这个值并不在(5, 8]这个区间里

    辅助索引 (xid 上面的索引) 中黄色部分是被 record lock锁住的行,除此之外还有两个 Gap Lock,锁住了上面说的范围

    先说为什么锁住了5的插入,观察主键索引,主键索引是自增的,因此在 id=4 这条记录之前,是不允许插入一条 xid=5 的记录的。

    反之,也就是说,间隙锁虽然是说是左开右闭实际上全是开区间!

    只不过,插入记录的主键大于行锁锁住的行主键就会等待锁,而小于行锁锁住的行主键就不会上锁!

    所以,本质上是两个条件:一个是间隙锁范围+行锁记录,还有一个是行锁记录的主键 id 和另一个要插入或者更新的主键 id 值有关

    不锁定xid=11的写入还是可以用 id 是自增的解释,B+ 树是有序的,并不会阻塞后续的插入

    参考

    next_key

    需要注意的是,如果索引有唯一属性,则 InnoDB 会自动将 Next-key Locks 降级为 Record Locks

  • 死锁

    InnoDB 引擎采取的是 wait-for graph 等待图的方法来自动检测死锁,如果发现死锁会自动回滚一个事务