讲师中心 微信公众号
AI工具推荐 视频效率加速

MySQL编写触发器需注意的锁表风险_避免触发器导致死锁方案

云晨君_2368

云晨君_2368

发布时间:2026-04-02 11:15:15

|

826人浏览过

|

来源于php中文网

原创

触发器执行时会隐式加行锁,非“只读操作”:访问表会加next-key lock,SELECT需显式加锁,避免全表扫描;禁双向跨表更新防死锁;函数调用不隔离锁;推荐应用层替代。

mysql编写触发器需注意的锁表风险_避免触发器导致死锁方案

触发器执行时会隐式加行锁,不是你想的“只读操作”

很多人写 BEFORE INSERT 触发器去校验数据、生成默认值,以为只是读几行、算个值,不会影响并发。实际上,MySQL 在触发器内部访问的每一张表(哪怕只是 SELECT),只要涉及索引查找或写入,都会在对应行上加 next-key lock —— 这是间隙锁 + 行锁的组合,会阻塞其他事务对同一范围的插入/更新。

常见错误现象:INSERT ... SELECT 语句卡住,SHOW ENGINE INNODB STATUS 显示 waiting for table metadata lock 或 lock wait timeout exceeded,但主 SQL 看不出明显锁冲突,根源往往在触发器里多查了一张配置表。

  • 触发器中所有 SELECT 必须带 FOR UPDATE 或 LOCK IN SHARE MODE 显式声明意图,否则 MySQL 默认按一致性读(MVCC)处理;但一旦触发器里有 UPDATE 或 INSERT,前面的 SELECT 就可能被升级为加锁读
  • 避免在触发器里查非主键字段(尤其是没索引的),否则容易升级为全表扫描+锁全表
  • 如果只是取一个固定配置值(如系统参数),优先用 SELECT ... INTO @var FROM DUAL 或直接硬编码,别查业务表

跨表更新触发死锁:两个触发器互相等待对方锁

典型场景:用户表 users 的 AFTER UPDATE 触发器去更新日志表 user_logs;而 user_logs 的 BEFORE INSERT 又反向查 users 做归属校验。此时两个事务 T1、T2 并发执行,就极易形成循环等待:T1 持有 users 行锁、等 user_logs 插入锁;T2 持有 user_logs 插入锁、等 users 行锁。

这种死锁不会报错“duplicate key”,而是直接 Deadlock found when trying to get lock,且 SHOW ENGINE INNODB STATUS 里能清晰看到两个事务各自持有的锁和等待的锁。

  • 触发器链路必须单向:A → B,禁止 B → A。如果真需要双向联动,改用应用层事务 + 显式顺序控制
  • 所有跨表操作,按固定顺序加锁:比如约定总是先锁 users,再锁 user_logs,所有触发器和应用代码都遵守
  • 用 SELECT ... FOR UPDATE 时,务必加上 ORDER BY primary_key,确保加锁顺序一致,避免因扫描顺序不同引发死锁

触发器里调用存储函数也可能锁表

你以为把复杂逻辑封装成函数就安全了?错。只要函数体内有 SELECT、UPDATE 等 DML,它在触发器里被调用时,锁行为完全继承上下文——也就是说,函数不是“隔离执行单元”,它和触发器共享同一事务和锁空间。

MySQL
MySQL

编写正确的MySQL查询,避免字符集、索引和锁方面的常见陷阱。

下载

常见错误现象:一个看似无害的 get_user_status(user_id) 函数,在高并发 INSERT 触发器里被频繁调用,结果 users 表的热点行被反复加锁,吞吐量断崖下跌。

  • 函数内禁止访问除参数外的任何表,除非你明确知道它会被用在触发器里,且已评估过锁影响
  • 若函数必须查表,优先走缓存(如应用层预加载到内存),或改用 SELECT ... INTO @var FROM DUAL 返回常量
  • MySQL 8.0+ 支持将函数标记为 READS SQL DATA 或 NO SQL,但这只是语法提示,不改变实际锁行为

替代方案比硬扛触发器更可靠

很多需求本质是“数据变更后同步动作”,比如写 binlog、发消息、更新搜索索引。这类场景下,触发器不是唯一解,反而最容易出问题。

真正可控的做法是:把逻辑从数据库层上提到应用层,用事务 + 异步任务兜底。例如,在应用里用 INSERT INTO users 后立即发一条 Kafka 消息,下游消费者负责写日志、更新 ES;失败可重试,不拖慢主流程。

  • 触发器无法回滚外部系统操作(比如已经发了 MQ 消息),而应用层事务可以统一管理 DB + MQ 生产者
  • 触发器调试困难,日志分散,线上出问题几乎没法实时 trace;应用层有完整链路追踪和监控
  • MySQL 主从复制中,触发器在从库是否执行取决于 binlog_format 和 log_bin_trust_function_creators,稍不注意就导致主从数据不一致

最麻烦的不是写不出来,而是写出来之后,没人敢动、不敢删、出了问题查三天还找不到源头 —— 尤其当多个触发器嵌套调用、又混着自定义函数时,锁行为基本不可预测。

热门AI工具

更多
Lovart
Lovart Hot

一款面向视觉设计创作的AI设计平台,可通过智能体和画布工作流辅助制作海报、Logo、网页、PPT及其他视觉内容。

二狗PPT
二狗PPT Hot

一款AI演示文稿工具,主要用于专为中式职场打造的AI PPT生成工具,适合需要提升相关任务效率的用户。

Atoms
Atoms Hot

Atoms是一款AI智能体工具,第一支自动构建真实业务的 AI 团队。

墨刀AI
墨刀AI Hot

一款AI图像与设计工具,主要用于产品经理的专属智能体,适合需要提升相关任务效率的用户。

PixTV
PixTV Hot

PixTV是一款面向AIGC内容创作的AI视频生成工具。

PixPix
PixPix Hot

PixPix是一款面向电商视觉生产的AI商品图生成工具。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

相关专题

更多
mysql修改数据表名
mysql修改数据表名

MySQL修改数据表:1、首先查看数据库中所有的表,代码为:‘SHOW TABLES;’;2、修改表名,代码为:‘ALTER TABLE 旧表名 RENAME [TO] 新表名;’。php中文网还提供MySQL的相关下载、相关课程等内容,供大家免费下载使用。

2293

2023.06.20

MySQL创建存储过程
MySQL创建存储过程

存储程序可以分为存储过程和函数,MySQL中创建存储过程和函数使用的语句分别为CREATE PROCEDURE和CREATE FUNCTION。使用CALL语句调用存储过程智能用输出变量返回值。函数可以从语句外调用(通过引用函数名),也能返回标量值。存储过程也可以调用其他存储过程。php中文网还提供MySQL创建存储过程的相关下载、相关课程等内容,供大家免费下载使用。

1399

2023.06.21

mongodb和mysql的区别
mongodb和mysql的区别

mongodb和mysql的区别:1、数据模型;2、查询语言;3、扩展性和性能;4、可靠性。本专题为大家提供mongodb和mysql的区别的相关的文章、下载、课程内容,供大家免费下载体验。

815

2023.07.18

mysql密码忘了怎么查看
mysql密码忘了怎么查看

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS 应用软件之一。那么mysql密码忘了怎么办呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

3172

2023.07.19

mysql创建数据库
mysql创建数据库

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS 应用软件之一。那么mysql怎么创建数据库呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

5408

2023.07.25

mysql默认事务隔离级别
mysql默认事务隔离级别

MySQL是一种广泛使用的关系型数据库管理系统,它支持事务处理。事务是一组数据库操作,它们作为一个逻辑单元被一起执行。为了保证事务的一致性和隔离性,MySQL提供了不同的事务隔离级别。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

1199

2023.08.08

sqlserver和mysql区别
sqlserver和mysql区别

SQL Server和MySQL是两种广泛使用的关系型数据库管理系统。它们具有相似的功能和用途,但在某些方面存在一些显著的区别。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

5671

2023.08.11

mysql忘记密码
mysql忘记密码

MySQL是一种关系型数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。那么忘记mysql密码我们该怎么解决呢?php中文网给大家带来了相关的教程以及其他关于mysql的文章,欢迎大家前来学习阅读。

4942

2023.08.14

Playwright 测试失败怎么办
Playwright 测试失败怎么办

Playwright测试失败专题汇集超时、定位器匹配、浏览器提前关闭、依赖与插件配置、文件上传、SSL及Docker启动等故障文章,并介绍通过截图、报告和Trace定位错误。

0

2026.10.21

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL vs MySQL
PostgreSQL vs MySQL

共1课时 | 188人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn