首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

程序员基础知识之数据库死锁

死锁,相信大家都不陌生,通俗易懂的讲,就是有双方都吃着自己碗里的,盯着对方碗里的,导致双方都没办法吃到所有的。

举个例子,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语句放在事务的后面,更有利于事务的执行效率。同时又减少了死锁发生的可能,一举两得。

其次,我们应该限制并发的数量,对于一些不那么重要的,或者客户可接受一定延迟的业务,采用限制并发或者串行化去执行。举个例子,像微博的粉丝,微信的公众号订阅数,我们可以采用串行化,然后合并进行统计。

今天我们介绍了数据库的死锁,希望对你有所帮助。欢迎大家关注我,共同学习,共同进步。大家的支持是我继续唠嗑的动力。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20200403A06DDC00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券