MySQL的锁(为什么有时候使用行锁for update会造成表锁)

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

全局锁

使用命令:Flush tables with read lock 或者set global readonly=true(推荐使用前者,因为后者的readonly字段可能要被用来做逻辑判断,并且前者锁支持手动和自动释放,但后者必须再次手动设置readonly,容易造成长事务

使用场景:全库逻辑备份

拥有事务功能的引擎使用single-transaction(事务+MVCC)进行全局锁,不支持事务就用Flush tables with read lock。

表级锁 (表锁与元数据锁MDL)

  • 表锁:
    lock tables t1 read, t2 write……
    lock tables 语法除了会限制别的线程的读写外,也限定了本线程接下来的操作对象

  • MDL:
    MDL 不需要显式使用,在访问一个表的时候会被自动加上。对一个表做增删改查操作的时候,加 MDL 读锁;当要对表做结构变更操作的时候,加 MDL 写锁。

    所以对表进行加减字段时容易导致线程阻塞(进行中的事务需要释放完所有读写锁MDL才能获取写锁,即写锁包含有读锁,并且MDL等待获取锁的过程中后续的事务不能开启)

行级锁

MySQL中的行锁是加在索引文件上的,所以当查询没有用上索引时,行锁不会生效转而变成表锁。

注意:当使用for update进行大量范围查询时,需要在索引上反复加多个行锁,大量消耗CPU资源,MySQL可能会自动优化放弃使用行锁,直接给全表加锁,可能这样查询速度会更快.。

并不是所有引擎都支持行锁

两阶段锁协议:在 InnoDB 事务中,行锁是在需要的时候才加上的(执行对应行的sql语句时),但并不是不需要了就立刻释放,而是要等到事务结束时才释放。(所以如果你的事务中需要锁多个行,要把最可能造成锁冲突、最可能影响并发度的锁尽量往后放,如果往前放的话事务锁住该行的时间就变长了)

死锁(看到下面这张图的时候感觉自己以前对死锁的理解更清楚了)
在这里插入图片描述

解决死锁的策略:

  • 直接进入等待,直到超时。(超时时间不好设置,不建议使用)
  • 发起死锁检测,发现死锁后,主动回滚死锁链条中的某一个事务,让其他事务得以继续执行。一般建议用主动死锁检测策略(默认开启),但是会消耗大量的cpu资源,特别是热点更新(特定的行记录被访问的频率高),解决办法可以通过使用中间件,对于向同行的更新进行排序。

ps: 锁这块理解的不深,后面一边实践一边继续学习。
参考文章:

https://time.geekbang.org/column/article/70215

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值