MySQL 锁机制

MySQL通过MVCC和锁机制实现事务的隔离性。对于MVCC之前的文章MySQL MVCC详解介绍过了,今天来讲讲MySQL的锁。

锁的分类

根据加锁思想可以分为悲观锁、乐观锁;
根据兼容性可以分为共享锁、排它锁;
按照粒度可以分为行锁、页锁、表锁。InnoDB支持行锁和表锁。

悲观锁和乐观锁

悲观锁

悲观锁基于一种悲观的态度来防止一切数据冲突,当要对数据库中的一条数据进行修改时会先对该数据进行加锁,避免被其它事务修改。MySQL中的行锁、表锁、读锁、写锁等等都是悲观锁。

乐观锁

乐观锁是对于数据冲突保持一种乐观态度,每次去拿数据的时候都认为不会被其它事务修改,所以不会上锁,但是在提交修改的时候会判断一下在此期间该数据有没有被修改过,一般使用版本号机制或CAS算法来实现。

应用场景

乐观锁适用于多读少写的场景,因为省去了加锁的开销,能够提高并发的性能。
多写的场景下用悲观锁比较合适,多写时会经常产生冲突,如果使用乐观锁会导致应用不断的进行重试,反而降低了性能。

共享锁和排它锁

共享锁

共享锁也叫读锁或S锁,当前事务获得S锁后,不会阻塞其它事务获得S锁,但会阻塞其它事务获得X锁。

排它锁

排它锁也叫独占锁、写锁或X锁,当前事务获得X锁后,会阻塞其它事务获得S锁和X锁。

隐式锁定和显式锁定

锁定类型和对应的SQL语句

  1. 显式读锁:select…lock in share mode,lock table…read
  2. 显式写锁:select…for update,lock table…write
  3. 隐式写锁:insert/update/delete

行锁和表锁

行锁

InnoDB引擎中有三种行锁的算法,如下:

Record Lock

Record Lock:记录锁,锁定的是单个索引记录。

Gap Lock

Gap Lock:间隙锁,锁定的是索引记录之间的间隙。给索引记录加Gap Lock时,会锁定该记录前面的间隙。

Next-key Lock

Next-key Lock:临键锁,Record Lock + Gap Lock 的组合,既锁定索引记录,又锁定前面的间隙。

使用场景

在RR事务隔离级别下,进行等值查询时,分为以下这些情况:

  1. 有匹配的索引记录
    1. 主键索引
      i. 给唯一匹配的索引记录加上Record Lock。
    2. 唯一索引
      i. 给唯一匹配的索引记录加上Record Lock;
      ii. 给对应的主键索引记录加上Record Lock。
    3. 普通索引
      i. 给所有匹配的索引记录都加上Next-key Lock,给下一个不匹配索引记录加上Gap Lock(给前后间隙都加上锁了,这样就可以防止插入相同索引值的记录,从而防止幻读 );
      ii. 给对应的主键索引记录都加上Record Lock。
    4. 没走索引
      i. 给所有主键索引记录和间隙都加锁。
  2. 无匹配索引
    1. 聚集索引、唯一索引、普通索引
      i. 给大于匹配值的第一个索引记录加上Gap Lock。
    2. 没走索引
      ii. 给所有主键索引记录和间隙都加锁。

表锁

表锁的加锁命令是lock tables … read/write,释放锁命令是unlock tables,在会话退出时也会自动释放表锁。因为表锁的粒度太大,会影响并发性能,所以应该尽量避免在 InnoDB 引擎中使用表锁。

MySQL中的其它表级锁还有意向锁,自增锁,元数据锁。

意向锁

当一个事务想要获得一个表锁时,需要先确认该表的所有记录都没有被其它事务加锁,如果一行行检测的话效率很低,这时就出现了意向锁。在给获得行上的锁之前必须先获得该表的意向锁,这样的话要获得表锁时只需要检测对应的意向锁就可以了。

意向锁分为意向共享锁、意向排它锁:

  1. 意向共享锁也叫IS锁,一个事务要获取行上的共享锁之前,必须先获取该表的IS锁或IX锁。
  2. 意向排它锁也叫IX锁,一个事务要获取行上的排它锁之前,必须先获取该表的IX锁。

意向锁的兼容性矩阵如下:

XIXSIS
XConflictConflictConflict
IXConflictCompatibleConflict
SConflictConflictCompatible
ISConflictCompatibleCompatible
元数据锁

元数据锁就是MDL(metadata lock),元数据锁主要解决DDL和DML同时执行的冲突问题。执行DML操作时会先在对应表上加一个metadata读锁,执行DDL操作时会先在对应表上加一个metadata写锁,这样DDL和DML就无法同时执行了。

自增锁

自增锁(AUTO-INC LOCK)的三种模式如下:

  1. 传统模式:如果一个事务向包含AUTO_INCREMENT列的表中插入数据会先去获得自增锁,语句执行完之后会释放,从而保证自增值是连续的。
  2. 连续模式(MySQL 8.0 之前的默认模式):如果 INSERT 语句可以提前确定插入的数据量,则不必获取自增锁,只是使用了mutex来防止ID重复分配,例如 INSERT INTO… 这种语句;如果 INSERT 语句不能提前确认插入的数据量,则还是会去获取自增锁,例如 INSERT INTO … SELECT … 这种语句。
  3. 交叉模式(MySQL 8.0 的默认模式):所有的 INSERT 语句都不会使用自增锁,而是使用较为轻量的 mutex 锁。

参考

MySQL :: MySQL 5.7 Reference Manual :: 14.7.1 InnoDB Locking
MySQL :: MySQL 5.7 Reference Manual :: 14.6.1.6 AUTO_INCREMENT Handling in InnoDB

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值