死锁的检测和案例
死锁
1. 什么是死锁
当并发系统中不同线程出现循环资源依赖,涉及的线程都在等待别的线程释放资源时,
就会导致这几个线程都进入无限等待的状态,称为死锁
T1 | T2 |
---|---|
begin | |
select * from t where i = 1 lock in share mode; | begin |
delete from t; 卡住 | |
DELETE FROM t WHERE i = 1; 可执行 | |
检测到死锁,回退事务 ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction |
2. 相关参数
相关参数:
- innodb_deadlock_detect | ON 控制死锁检测的开启;如在高并发的场景下建议关闭死锁检测
如果检测到死锁,会马上抛出异常,回滚一个事务(影响较小的事务,比如产生undo较少的事务),另一个事务继续执行; - innodb_status_output_locks | on : show engine innodb status \G;只显示最后的死锁信息(事务中);
- innodb_print_all_deadlocks | on ;开启后会将死锁的全部信息打印到错误日志文件中
- innodb_lock_wait_timeout default 50s ;锁超时时间
3. 避免死锁
避免死锁
1)以固定的顺序访问表和行。简单方法是对id列表先排序,后执行,这样就避免了交叉等待锁的情形;
2)大事务拆小。大事务更倾向于死锁。
3)在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁概率。
4)降低隔离级别。如果业务允许,将隔离级别调低也是较好的选择,比如将隔离级别从RR调整为RC,可以避免
掉很多因为gap锁造成的死锁。
5)为表添加合理的索引。可以看到如果不走索引将会为表的每一行记录添加上锁,死锁的概率大大增大
4. 死锁处理
查看事务
select * from information_schema.INNODB_TRX;
– 查看锁
select * from information_schema.INNODB_LOCKS;
– 查看锁等待
select * from information_schema.INNODB_LOCK_WAITS;
- 看近期死锁日志信息
show engine innodb status \G;
- 锁释放 information_schema.INNODB_TRX 查询 trx_mysql_thread_id 然后去 kill 对应的value
kill trx_mysql_thread_id
- 锁等待有自己的超时时间,超过后一般都会自动释放
mysql> select * from t where id =2 for update ;
1205 - Lock wait timeout exceeded; try restarting transaction