InnoDB|S 锁与 X 锁的爱恨情仇《死磕MySQL系列 四》( 三 )


过程示例:新来的线程F , 被锁了后就要检查锁住F的线程(假设为D)是否被锁 , 如果没有被锁 , 则没有死锁 , 如果被锁了 , 还要查看锁住线程D的是谁 , 如果是F , 那么肯定死锁了 , 如果不是F(假设为B) , 那么就要继续判断锁住线程B的是谁 , 一直走知道发现线程没有被锁(无死锁)或者被F锁住(死锁)才会终止
问题:平时在开发中使用那种方案呢?
存在必合理 , 一般情况还是采用第二种方式 , 这种方式在有死锁时是能够快速进行处理的 。
作为开发者肯定听过一句这样的话要么用空间换时间 , 要么用时间换空间 。 两者只可兼一种 。
这种方式虽可以非常迅速的处理死锁问题 , 同样也会带来额外的负担 。
思考:带来了那些额外的负担?
假设你负责的业务都需要更新同一行数据 。
此时按照第二种方式 , 当发现死锁后 , 主动回滚死锁链条的某一个事务 , 那么 , 每一个进来被堵住的线程 , 都要判断是不是由于自己的加入导致死锁 , 这个时间复杂度是O(n)的操作 。
假设有1000个线程都在更新同一行 , 操作的数据量是100W , 检测出来死锁消耗资源还不怕 , 若最终检测结果没有死锁 , 这个期间消耗的CPU资源是非常高的 。
就如何解决这种问题再进行谈论一下 。
六、如何解决热点数据的更新为什么要聊这个问题
使用了第二种方案来解决死锁 , 热点数据死锁检测会非常消耗CPU(每一个进来被堵的线程都会检测是不是由于自己的加入导致的死锁 , 有可能是锁等待 , 但还是需要做判断 , 所以非常消耗CPU) , 所以针对这个问题进行简单讨论一下 。
咔咔在其它资料中看到有三种方案 。
1.关闭死锁检测
2.控制并发度
3.修改MySQL源码对于更新同一行数据 , 在进入引擎之前排队 。 这样就不会出现大量的死锁检测
方案一:关闭死锁检测不考虑
这种方式会出现大量的超时 , 降低了用户体验 , 一般情况死锁不会对业务产生严重错误 , 毕竟出现死锁 , 数据大不了回滚即可 。
方案二:控制并发度
可以把商家账户分散多个 , 所有的账户之和为账户余额 。
例如分了10个子账户 , 那么出现更新同一行数据的概率就降低了10倍 , 这种方式在业务处理时需要简单处理一下 。 防止账户余额为0时用户发起退款的逻辑处理 。
这种方式还是很建议大家使用的 , 从设计上降低死锁发生 。
方案三:修改MySQL源码
大多数公司连DBA都没有 , 何谈存在可以修改MySQL源码的人 , 这种对于企业的成本是非常大的 , 而且也没那个必要 。
修改MySQL源码想要实现的功能是当更新同一行数据时 , 在进入存储引擎之前排队 。
这种方案用队列完全可以解决 , 所以并不需要从根上解决这个问题 。
七、总结
本期从行锁出发引出了两阶段锁 , 明白了事务提交后才会释放锁 。
死锁的产生 , 如何从代码的角度来减少死锁的产生 。
MySQL也给提供了两种方案来解决死锁问题 , 对于这两种方案咔咔也给了不同的观点 。 根据自己的情况来使用 。
在这期文章中并没有演示死锁案例 , 在后边的文章中咔咔会给大家列举几种典型的死锁案例 。
【InnoDB|S 锁与 X 锁的爱恨情仇《死磕MySQL系列 四》】坚持学习、坚持写作、坚持分享是咔咔从业以来所秉持的信念 。 愿文章在偌大的互联网上能给你带来一点帮助 , 我是咔咔 , 下期见 。