美文网首页MySQL
浅析MYSQL行级锁特性

浅析MYSQL行级锁特性

作者: Stevennnmmm | 来源:发表于2020-02-10 12:55 被阅读0次

    什么是锁?

    为什么会出现锁这个东西呢,我们知道数据库是一个共享的数据池,当多个线程都读取同一个数据的时候难免会发生抢占。那么我们的锁就是出来为了解决这个问题的。一般来说mysql分为:全局锁,表锁,行锁,我们讲一下我们常见的行锁吧,一般的话我们通常见到的也是行级锁的问题。

    两阶段锁

    image.png

    我们可以看出图中行id=1的时候会发生行锁,此时我们的事务B就必须等待事物A完成后才能进行。此时事物A拥有两个行锁:行id=1,id=2 两个行锁,而且必须等待事物提交后才会释放锁。
    这也就是两阶段锁

    在innodb事务中,行锁是在需要的时候才加上的,但并不是不需要了就立即释放,
    而是要等到事务结束时才释放,这就是两阶段锁
    

    事务中排序数据库操作顺序

    当我们知道了这个两阶段锁特性后,我们就可以进行常用查询的优化了。此时我们就需要按照一些原则进行查询优化。
    这里我们提一个案例:用户A通过支付宝给用户B转了一笔账,假设用户B是个生意老板,分分钟几百笔进账的那种


    image.png

    此时我们有3个步骤:
    1.减少用户A的存款
    2.增加用户B的存款
    3.记录交易日志

    此时我们对这种操作一般都会用事物来保证一致性。
    那么我们在代码中应该如何置放1.2.3的顺序呢。
    B用户的收账是比较频繁的步骤,日志记录是新增操作不需要锁行,A用户相对没那么频繁的账户操作,那么我们应该这么进行代码放置:
    3,1,2 这样我们锁住B的余额的时间最短,在高频请求下可以大大增加代码的并发度。

    死锁和死锁检查

    首先我们看一下什么是死锁


    image.png

    当我们有两个事务AB的时候,很不幸的有着类似或者相同的业务的时候,我们可能会发生这种事情:事务A要修改id=2的时候需要事务B释放行锁,事务B要修改id=1的时候需要事务A释放行锁,两个事务相互纠缠就形成了死锁。

    那么我们的系统有什么自查功能呢

    1.直接进入等待状态,直到超时,可以通过参数innodb_lock_wait_time进行设置,默认时间50秒
    2.另一种策略是死锁检测,innodb发现死锁后主动回滚某一个请求链条的事务,让其它事务继续执行,将参数innodb_deadlock_detect 设置成on
    

    一般来说两种方法我们会选择后者。
    在innodb中我们用第一种默认50秒的解决方案实际上对线上服务很不友好,假如我们有两个线程发生了这两个事务,那么就意味着其他线程就访问不了,要默认等待50s,对用户来说根本是不能接受的。那么我们把锁等待值设置很小,比如一秒呢。这种解决方案也是不可取的,如果是简单的锁等待,没有死锁,那么一个事物还在执行期间行锁就被解开,万一该事务失败,数据回滚就会发生数据错误,也就破坏了事物的一致性原则。

    那么我们用主动死锁检测吗?其实mysql配置中innodb_deadlock_detect 默认是开的,但是它也是有负担的,每个请求下:新进入innodb的线程都要判断由自己的加入导致死锁,这个是一个时间复杂度在On的操作,有1000个并发线程同时更新一行,那么死锁检测就是百万量级,这期间要消耗大量的cpu,这时候就会发现cpu很高,却执行不了几个事务。如果我们能确定代码的操作流程绝对不会造成死锁,我们甚至可以兵行险着,关闭掉这个选项。

    相关文章

      网友评论

        本文标题:浅析MYSQL行级锁特性

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