请选择 进入手机版 | 继续访问电脑版
在线投稿 文字标题 文字标题 文字标题 文字标题 文字标题
切换皮肤
死锁,相信大家都不陌生,通俗易懂的讲,就是有双方都吃着自己碗里的,盯着对方碗里的,导致双方都没办法吃到所有的。
?url=http%3A%2F%2Fdingyue.ws.126.net%2F2020%2F0403%2Ff785f891p00q86v1e01fqc000yg00mwm.jpg

举个例子,A在商家买了一个东西,会完成一系列非常复杂的数据库操作,我们可以简化为如下两个操作,A的账户金额-50,然后商家的金额正在50。与此同时,商家小二恰好也完成这样的一次操作,审核了A的一笔退款,于是商家的金额减100,A账户的金额增加100。于是,前面一次操作取得了修改A账户的行锁,将A的账户减少50,但是事务并没有完成,需要往商家账户增加50。后面一次操作取得了商家的行锁,将商家的账户减去100,当是事务同样也没有完成,需要等待取得A的行锁,然后账户金额增加100。
就这样,前面的事务取到用户的行锁,等着商家的锁,后面的事务取得商家的锁,等着用户的锁,两个人都无法得到满足,事务无法完成,形成死锁。那么Mysql遇到死锁的时候,会怎么办呢?
MySQL是由这样一个配置的,innodb_lock_wait_timeout。也就是说,如果双方僵持不下,超过这个时间之后,双方就放手,再来一次,万一这一次不冲突啦。但是,如果这个时间太长,我们总不能让用户等个几十秒再重试吧,如果我们把这个时间设置得太短,那么又可能照成误伤,本来这个执行语句就要执行2秒,结果设置超时时间是1秒,最后事务回滚,等于白干。
MySQL还提供另外一个功能,就是检查死锁,innodb_deadlock_detect,如果我们把这个开关打开的时候,每当执行一个语句拿不到锁的时候,就会去遍历其他线程,看看是不是发生死锁了。一般情况下,我是不建议打开这个开关的,举个例子,假如有1000个线程同时更新同一行,每个事务其实只是干1个事情,单因为其他999个线程拿不到锁,就要互相遍历,看看是否形成死锁,造成极大的开销。
那么,我们如何避免这种遇到死锁的情况呢?我觉得,应该在业务设计的时候,就尽量去避免出现死锁的可能。首先,我们应该避免上述例子中这种不合理的设计,为什么我们不能够付款跟退款都设计成先操作用户金额,再操作商家金额呢?前面我们也提到过,将并发度高的Sql语句放在事务的后面,更有利于事务的执行效率。同时又减少了死锁发生的可能,一举两得。
其次,我们应该限制并发的数量,对于一些不那么重要的,或者客户可接受一定延迟的业务,采用限制并发或者串行化去执行。举个例子,像微博的粉丝,微信的公众号订阅数,我们可以采用串行化,然后合并进行统计。
今天我们介绍了数据库的死锁,希望对你有所帮助。欢迎大家关注我,共同学习,共同进步。大家的支持是我继续唠嗑的动力。同名公众号(沙茶敏碎碎念)

回复

使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则


    Archiver|手机版|小黑屋|齐聚无忧 |网站地图

    Powered by Discuz! X3.4  © 2001-2013 Comsenz Inc.