【每日一题】形成数据库死锁的原因有哪些?如何能避免死锁

Posted by 石福鹏 on 2020-09-24

1、什么是死锁

会话A持有一行数据的锁,会话B持有另一行数据的锁。 A申请获取B持有的那个锁,但是被B占用着,所以A等待。 B申请获取A持有的那个锁,但是被A占用着,所以B等待。

2、死锁的本质

两个或多个会话/线程,本身拥有一个锁,但是去互相申请对方拥有的锁,导致都在锁等待,即为死锁。索引失效会造成表锁,比死锁更严重

3、举例

在RR隔离级别下,数据库有两条数据id=1和id=10。 且id为普通索引 两个事务,事务 1: select * from table where id=3 for update。 insert (id=3),他会在(1,3) (3,10)之间加间隙锁,在(3)这个位置申请插入意向锁。 事务2: select * from table where id=5 for update, insert(id=5)。 它会在(1,5) (5,10)之间加间隙锁,由于间隙锁互相兼容,故该锁可以获取,另外在(5)这个地方申请插入意向锁。 当事务1要获取插入意向锁时,发现(3)被事务2的间隙锁锁住了,故等待事务2释放锁; 事务2要获取插入意向锁时,发现(5)被事务1的间隙锁锁住了,故等待事务1释放锁;——死锁形成

4、InnoDB的死锁检测

InnoDB内部会自动识别死锁,并回滚其中一个权重较小的事务。一般为修改量最小的,undo log最小的。

5、避免死锁

①、注意sql的执行顺序,尽量让sql以相同顺序获取数据,

②、大事务化为小事务,减少持有锁的时间,

③、加快sql执行速度,优化sql,包括建立索引,

④、优化表结构,可一定程度上避免死锁