一、问题
数据库的死锁是怎么产生的?两个事务抢锁,谁也不让谁就产生死锁了。
出现死锁了怎么排查和解决?
二、死锁的原理
死锁的原理特别好理解,比如:你和朋友去吃饭,你拿了筷子,他拿了碗,你要等他的碗才能吃饭,他要等你筷子才能吃饭,你们两个谁也不松手,然后就僵在这里了,这个就是死锁。
对应到数据库里面,必须同时满足 4 个条件才会出现死锁:
互斥条件:一个锁同一时间只能被一个事务持有,就像筷子同一时间只能由一个人去用
持有并等待:我已经拿了一个锁,还要等着拿另一个锁,手里的锁呢我还不松手
不可剥夺:别人拿的锁我不能硬抢,只能等别人自己释放
循环等待:a 等 b 的锁,b 等 a 的锁,形成了一个死循环
这 4 个条件同时满足就形成了死锁。
三、死锁的解决
3.1、SQL
show engine innodb status
这个语句会清楚的告诉你哪两个事务产生了死锁,这个两个事务分别执行了什么 SQL,抢的是什么类型的锁,最后数据库自动回滚了哪一个事务
3.2、业务代码找问题
拿着死锁的日志里面的两个 SQL 语句,去找对应的业务代码。
90% 的情况都是事务执行顺序反了:比如说事务 1 先改订单表,再改用户表;事务 2 先改用户表,再改订单表;刚好形成一个循环等待
3.3、检查不必要锁
看是不是锁的粒度太大了:比如明明应该加行锁的,结果因为字段没有加索引,导致了锁所有的行。
普通查询加了一些没必要的悲观锁:比说 for update 导致锁的范围变大了,更容易产生冲突
mysql 第8.17章 事务-死锁