本文基于MySQL 5.7.11的默认引擎InnoDB 1.2.x ,从复现问题(模拟阻塞与死锁)、产生原因、解决办法、编码建议等角度全面解析阻塞和死锁;
第四节也会提及使用命令和INFORMATION_SCHEMA下的表来查看事务&锁的情况。
目录
1. 阻塞
首先明确一点,阻塞与死锁是不同的。但它俩发生的场景往往相同:通常都在最糟糕的时候发生,比如产线业务最繁忙、高并发的场景下 🤭。
阻塞是 InnoDB 引擎的正常行为,它为了确保事务可以正常并发,保证数据一致性等;
但会影响性能,尤其在高并发情况下。两者差异如下图
特性 | 阻塞 | 死锁 |
---|---|---|
定义 | 事务等待资源释放,才能继续执行 | 两个或多个事务互相等待对方持有的资源,形成循环等待。 |
发生条件 | 事务请求锁时,资源已被其他事务锁定。 | 事务之间相互等待对方的锁,并且没有办法继续执行。 |
处理方式 | 事务会在锁释放后继续执行,或者等待超时抛出异常 | MySQL 自动检测并回滚一个事务,以解决死锁问题。 |
性能影响 | 会导致事务等待,延迟响应,可能影响整体系统性能。 | 死锁回滚需要额外的时间和资源,可能影响事务的响应时间。 |
发生概率 | 常见,特别是在高并发情况下。 | 较少发生,但一旦发生,通常需要手动优化事务的执行顺序。 |
影响范围 | 一般影响单个事务的执行,但不会导致系统崩溃。 | 死锁可能导致多个事务的失败,影响系统稳定性。 |
1.1 阻塞配置
InnoDB中有俩参数来控制阻塞的时间和策略。
- innodb_lock_wait_timeout 用来控制等待时间,默认是50秒,可动态设置Session | Global级;Global在重启后将丢失;Global修改时在这期间存活的Session也是不生效的;也可通过配置文件静态修改。
- innodb_rollback_on_timeout 控制等待超时的事务是否回滚,默认是OFF 不回滚;该参数为只读,不支持动态设置;需要在 MySQL 的配置文件(通常是
my.cnf
或my.ini
)中进行修改,然后重启服务才生效。
备注:有些文章甚至GPT 有关innodb_rollback_on_timeout 都说支持动态设置。其实官网对这俩参数的配置和作用说的很清楚,附上
用以下命令动态设置Session级等待时间,设置global级只需换成 set @@global.X = Y
-- 查看等待时间
SHOW VARIABLES LIKE 'innodb_lock_wait_timeout';
-- 设置等待时间
SET @@session.innodb_lock_wait_timeout = 10;
