MySQL触发器如何引发死锁?如何定位锁冲突及提升并发写入效率?
- 内容介绍
- 文章标签
- 相关推荐
本文共计1255个文字,预计阅读时间需要6分钟。
MySQL触发展器本身不开启新事务,但它在父事务上下文中执行,所有SQL操作共享同一事务ID和锁生命周期。一旦触发展器内部包含UPDATE、INSERT或带有FOR UPDATE的查询,就会在原事务基础上新增锁请求。这些锁需要等待整个事务COMMIT或ROLLBACK后才能释放。
常见错误现象:Deadlock found when trying to get lock 报错中,死锁链里总有一个事务的 SQL 显示为触发器内部语句(如 UPDATE order_log SET status = 'processed' WHERE order_id = NEW.id),但应用层日志只记录了主表的 INSERT。
- 触发器中的 DML 不受应用层事务控制粒度约束,容易“偷偷加锁”
- 若触发器更新的是另一张高频写入表(如统计表、日志表),极易与外部事务形成交叉锁
- RR 隔离级别下,触发器里的范围查询(如
WHERE created_at > DATE_SUB(NOW(), INTERVAL 1 DAY))会触发Gap Lock,锁住间隙而非单行
多个触发器级联调用时锁顺序不可控
当一张表上定义了 BEFORE INSERT 和 AFTER INSERT 两个触发器,且后者又去更新第三张表,而该表上也有触发器——这种级联会放大锁路径复杂度。InnoDB 不会为触发器单独做锁排序优化,它只按实际执行顺序加锁。
本文共计1255个文字,预计阅读时间需要6分钟。
MySQL触发展器本身不开启新事务,但它在父事务上下文中执行,所有SQL操作共享同一事务ID和锁生命周期。一旦触发展器内部包含UPDATE、INSERT或带有FOR UPDATE的查询,就会在原事务基础上新增锁请求。这些锁需要等待整个事务COMMIT或ROLLBACK后才能释放。
常见错误现象:Deadlock found when trying to get lock 报错中,死锁链里总有一个事务的 SQL 显示为触发器内部语句(如 UPDATE order_log SET status = 'processed' WHERE order_id = NEW.id),但应用层日志只记录了主表的 INSERT。
- 触发器中的 DML 不受应用层事务控制粒度约束,容易“偷偷加锁”
- 若触发器更新的是另一张高频写入表(如统计表、日志表),极易与外部事务形成交叉锁
- RR 隔离级别下,触发器里的范围查询(如
WHERE created_at > DATE_SUB(NOW(), INTERVAL 1 DAY))会触发Gap Lock,锁住间隙而非单行
多个触发器级联调用时锁顺序不可控
当一张表上定义了 BEFORE INSERT 和 AFTER INSERT 两个触发器,且后者又去更新第三张表,而该表上也有触发器——这种级联会放大锁路径复杂度。InnoDB 不会为触发器单独做锁排序优化,它只按实际执行顺序加锁。

