> 文章列表 > 死锁的检测和案例

死锁的检测和案例

死锁的检测和案例

死锁

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