美文网首页
6.更新行时候的行锁

6.更新行时候的行锁

作者: 胖达_4b7e | 来源:发表于2019-01-18 14:09 被阅读0次

    行锁在引擎层由各个引擎自己实现的,MyISAM 引擎就不支持行锁

    调整语句顺序,使某行锁时间尽量短


    事务B 的更新操作会被阻塞, 直到事务A提交,
    事务A依次得到了id为1,2 共2行的锁, 提交后才释放 ,
    如果事务A的2条更新语句反一下, 先锁id=2 再锁id=1 ,那么id=1这行被锁住的时间就会短一些

    如下一个事务:
    1.从顾客 A 账户余额中扣除电影票价;

    2.给影院 B 的账户余额增加这张电影票价;

    3.记录一条交易日志。

    如果同时有另外一个顾客 C 要在影院 B 买票,那么这两个事务冲突的部分就是语句 2 了, 都要改影院B,需要影院B这行被锁的时间尽量短, 需要把语句2尽量靠后,如312 ,132

    死锁

    事务A:有第一行,等第二行
    事务B:有第二行,等第一行

    办法
    1.innodb_lock_wait_timeout 设最大等待时间, 但是不好把握到达设多少时长
    2.死锁检测:一般是用这个, innodb_deadlock_detect 的默认值本身就是 on。主动死锁检测在发生死锁的时候,是能够快速发现并进行处理的

    死锁检测的负担

    每当一个事务被锁(进入堵塞)的时候,就要看看它所依赖的线程(有我等待的那行锁的事务)有没有被别人锁住,如此循环,判断是否出现了循环等待(死锁)

    如:
    事务A得到第一行的锁, 堵塞在等待第二行的锁, 发现第二行的锁是被事务B拥有, 接着检查事务B有没有也在阻塞着等某行的锁, 发现事务B在等第一行的锁, 循环等待了

    所有事务都要更新同一行的场景:
    每个新来的被堵住的线程,都要判断会不会由于自己的加入导致了死锁(已经堵住的其他事务的线程,有没有需要新来的已有的锁的),这是一个时间复杂度是 O(n) 的操作。
    假设有 1000 个并发线程要同时更新同一行,那么死锁检测操作就是 100 万这个量级的。虽然最终检测的结果是没有死锁,但是这期间要消耗大量的 CPU 资源。因此,你就会看到 CPU 利用率很高,但是每秒却执行不了几个事务。

    解决方法

    1. 能确保这个业务一定不会出现死锁,可以临时把死锁检测关掉。

    2. 控制并发度。根据上面的分析,比如同一行同时最多只有 10 个线程在更新,那么死锁检测的成本很低,就不会出现这个问题。
      一个直接的想法就是,在客户端做并发控制。但是,你会很快发现这个方法不太可行,因为客户端很多。我见过一个应用,有 600 个客户端,这样即使每个客户端控制到只有 5 个并发线程,汇总到数据库服务端以后,峰值并发数也可能要达到 3000。
      并发控制要做在数据库服务端。如果你有中间件,可以考虑在中间件实现

    3. 将一行改成逻辑上的多行来减少锁冲突。

    相关文章

      网友评论

          本文标题:6.更新行时候的行锁

          本文链接:https://www.haomeiwen.com/subject/eaogdqtx.html