MySQL 中的锁


根据加锁的范围,MySQL 的锁大致可以分成全局锁、表级锁和行锁三类。

全局锁

全局锁就是对整个数据库实例加锁。可以使用 Flush tables with read lock(FTWRL) 加一个全局锁。这时整个数据库就处在只读状态。一般在做全库逻辑备份的时候会使用到全局锁。

当然,当使用支持事务的引擎时,我们可以使用事务的方式来保证备份期间的一致性。但如果当前引擎不支持事务,只能使用 FTWRL。

让整个数据库就处在只读状态还有另一种方式:set global readonly = true,但不建议使用,主要有两个原因:

  1. 在有些场景中,readonly 的值会被用来做其他逻辑,比如用来判断一个库是主库还是备库。因此,修改 global 变量的方式对整个数据库影响的范围更大。
  2. 在异常处理机制上有差异。如果执行FTWRL命令之后由于客户端发生异常断开,那么MySQL会自动释放这个全局锁,整个库回到可以正常更新的状态。而将整个库设置为readonly之后,如果客户端发生异常,则数据库就会一直保持readonly状态,这样会导致整个库长时间处于不可写状态,风险较高。

表级锁

表锁

表锁的语法是 lock tables … read/write。与 FTWRL 类似,可以用 unlock tables 主动释放锁,也可以在客户端断开的时候自动释放。

lock tables 除了会限制别的线程的读写外,也限定了本线程接下来的操作对象。

元数据锁

元数据锁,meta data lock,MDL。MDL不需要显式使用,在访问一个表的时候会被自动加上。MDL的作用是保证读写的正确性

当对一个表做增删改查操作的时候,加MDL读锁;当要对表做结构变更操作的时候,加MDL写锁

  • 读锁之间不互斥,可以有多个线程同时对一张表增删改查,注意 MDL 是表锁
  • 读写锁、写锁之间互斥,用来保证变更表结构操作(DDL)的安全性。

事务中的MDL锁,在语句执行开始时申请,但是语句结束后并不会马上释放,而会等到整个事务提交后再释放

所以,当某些线程进行增删改查操作,一些线程作DDL操作可能会造成整个库挂掉了。

行锁

行锁就是针对数据表中行记录的锁。比如事务A更新了一行,而这时候事务B也要更新同一行,则必须等事务A的操作完成后才能进行更新。

InnoDB 是支持行锁的,但 MyISAM 不支持行锁。

在 InnoDB 事务中,行锁是在需要的时候才加上的,但并不是不需要了就立刻释放,而是要等到事务结束时才释放。所以,如果事务中需要锁多个行,要把最可能造成锁冲突、最可能影响并发度的锁尽量往后放。

此外,当并发系统中不同线程出现循环资源依赖,涉及的线程都在等待别的线程释放资源时,就会导致这几个线程都进入无限等待的状态,称为死锁。

死锁以后,有两种策略:

  • 一种策略是,直接进入等待,直到超时。这个超时时间可以通过参数 innodb_lock_wait_timeout 来设置。
  • 另一种策略是,发起死锁检测,发现死锁后,主动回滚死锁链条中的某一个事务,让其他事务得以继续执行。将参数 innodb_deadlock_detect 设置为 on,表示开启这个逻辑,此参数默认值为 on。死锁检测能够快速发现并进行处理的,但是有额外负担。每个新来的被堵住的线程,都要判断会不会由于自己的加入导致了死锁,这个操作的时间复杂度是O(n)。这种线程越多,死锁检测就越多,会消耗大量的CPU资源

next-key lock

next-key lock 是用来解决幻读的。

幻读指的是一个事务在前后两次查询同一个范围的时候,后一次查询看到了前一次查询没有看到的行。注意:

  1. 在可重复读隔离级别下,普通的查询是快照读,是不会看到别的事务插入的数据的。因此,幻读在“当前读”下才会出现。
  2. 幻读仅专指“新插入的行”。

当前读的规则,就是要能读到所有已经提交的记录的最新值。

幻读会破坏语义,并且,幻读会破坏数据的一致性。

产生幻读的原因是,行锁只能锁住行,但是新插入记录这个动作,要更新的是记录之间的“间隙”。为了解决幻读问题,InnoDB引入间隙锁(Gap Lock)。间隙锁一般是前开后开的。

跟间隙锁存在冲突关系的,是“往这个间隙中插入一个记录”这个操作。间隙锁之间都不存在冲突关系

间隙锁和行锁合称next-key lock,每个next-key lock是前开后闭区间

间隙锁的引入,可能会导致同样的语句锁住更大的范围,会影响并发度。

注意,间隙锁在可重复读隔离级别下才会生效。

参考资料

《MySQL 45讲》

《MySQL 必知必会》

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值