0

0

mysql中触发器与事务隔离的配合使用

P粉602998670

P粉602998670

发布时间:2026-01-11 05:21:13

|

503人浏览过

|

来源于php中文网

原创

是的,MySQL中BEFORE和AFTER触发器均运行在触发SQL所属的同一事务内,共享提交、回滚及隔离级别约束,不可开启新事务,也不能即时感知同事务内的DDL变更。

mysql中触发器与事务隔离的配合使用

触发器执行时是否在当前事务内

是的,MySQL 中的 BEFOREAFTER 触发器都运行在触发它的 SQL 语句所属的同一事务中。这意味着:如果触发器内部修改了数据(比如 INSERTUPDATE),这些修改会和主语句一起提交或回滚;如果触发器抛出异常(例如通过 SIGNAL),整个事务会失败。

常见误解是“触发器自动开启新事务”,实际完全不是——MySQL 不允许在普通表触发器里显式使用 START TRANSACTIONCOMMIT,否则会报错:ERROR 1305 (42000): SAVEPOINT does not exist 或更直接的 ERROR 1305 (42000): Function 'COMMIT' does not exist

  • 触发器不能控制事务边界,它只是事务中的一个逻辑扩展
  • BEFORE 触发器可以修改 NEW 行值,影响后续主语句行为
  • AFTER 触发器无法修改正在被处理的行,但可操作其他表或发信号
  • 若主语句是批量操作(如 UPDATE ... LIMIT 100),触发器对每一行都单独执行一次

READ COMMITTED 隔离级别下触发器读不到未提交变更

当触发器内部执行 SELECT 查询(比如校验关联表状态),其可见性受当前会话的事务隔离级别约束。在 READ COMMITTED 下,触发器里的 SELECT 只能看到已提交的数据,**看不到同一事务中前面语句刚做的、尚未提交的修改**。

这会导致典型问题:主语句先 INSERT INTO orders,触发器紧接着 SELECT COUNT(*) FROM orders WHERE user_id = ? 去统计,结果为 0——因为该 INSERT 还没提交,而触发器的 SELECTREAD COMMITTED 下不加锁也不读未提交版本。

  • 解决方法之一:改用 REPEATABLE READ 隔离级别,它保证事务内多次 SELECT 看到相同快照
  • 更稳妥做法:避免在触发器里查本事务刚写入的表;改用传参方式(如把计数逻辑提到应用层)
  • 注意:SELECT ... FOR UPDATE 在触发器里仍受隔离级别限制,不会突破 READ COMMITTED 的可见性规则

触发器中调用存储函数可能引发死锁或一致性风险

如果触发器调用了含 SELECT ... FOR UPDATE 或写操作的存储函数,且该函数访问了与主语句相同的行或索引范围,极易触发死锁。尤其在高并发更新同一张表时,不同会话的触发器可能按不同顺序加锁。

启科网络PHP商城系统
启科网络PHP商城系统

启科网络商城系统由启科网络技术开发团队完全自主开发,使用国内最流行高效的PHP程序语言,并用小巧的MySql作为数据库服务器,并且使用Smarty引擎来分离网站程序与前端设计代码,让建立的网站可以自由制作个性化的页面。 系统使用标签作为数据调用格式,网站前台开发人员只要简单学习系统标签功能和使用方法,将标签设置在制作的HTML模板中进行对网站数据、内容、信息等的调用,即可建设出美观、个性的网站。

下载

例如:用户表 users 上有 AFTER UPDATE 触发器,调用函数 update_user_stats(user_id),而该函数又对 user_stats 表执行 UPDATE ... WHERE user_id = ?。若两个事务同时更新不同 user_id 但碰巧触发器函数访问了相同二级索引间隙,就可能因锁顺序不一致导致死锁。

  • 优先用纯计算型函数,避免在触发器中做额外 DML
  • 必须写数据时,确保锁顺序固定(如始终按 user_id ASC 更新相关表)
  • 监控 SHOW ENGINE INNODB STATUS 中的 LATEST DETECTED DEADLOCK 区域
  • 不要依赖触发器实现跨表强一致性——外键 + 应用层事务更可控

MySQL 8.0+ 的原子性 DDL 对触发器的影响

MySQL 8.0 引入了原子性 DDL,意味着 CREATE TRIGGERDROP TRIGGER 本身也运行在事务内。但这不改变触发器执行时的行为逻辑,只影响元数据变更的可靠性。

真正要注意的是:如果你在事务中执行了 ALTER TABLE ... ADD COLUMN,然后立即在同一个事务里尝试用触发器引用这个新列(如 NEW.new_col),会报错:ERROR 1363 (HY000): There is no NEW row in on INSERT trigger 或更常见的 ERROR 1363 (HY000): There is no OLD row in on INSERT trigger —— 实际原因是列尚未对触发器上下文可见,DDL 和触发器编译存在时序差。

  • DDL 和 DML 必须分两个事务执行;触发器无法“即时”感知同事务内的表结构变更
  • 升级 MySQL 版本后,检查旧触发器是否用了已被弃用的语法(如 DEFINER 权限不足)
  • information_schema.TRIGGERS 表在事务中查不到未提交的触发器定义
DELIMITER $$
CREATE TRIGGER check_balance_before_insert
    BEFORE INSERT ON accounts
    FOR EACH ROW
BEGIN
    DECLARE current_balance DECIMAL(10,2);
    -- 在 REPEATABLE READ 下才能读到本事务之前 INSERT 的余额
    SELECT balance INTO current_balance
        FROM accounts WHERE user_id = NEW.user_id;
    IF current_balance + NEW.amount < 0 THEN
        SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Insufficient balance';
    END IF;
END$$
DELIMITER ;

触发器不是事务控制器,它只是嵌在事务里的自动代码段。真正容易被忽略的是:它的查询可见性完全由会话隔离级别决定,而不是“因为是触发器所以能看见一切”。

相关专题

更多
数据分析工具有哪些
数据分析工具有哪些

数据分析工具有Excel、SQL、Python、R、Tableau、Power BI、SAS、SPSS和MATLAB等。详细介绍:1、Excel,具有强大的计算和数据处理功能;2、SQL,可以进行数据查询、过滤、排序、聚合等操作;3、Python,拥有丰富的数据分析库;4、R,拥有丰富的统计分析库和图形库;5、Tableau,提供了直观易用的用户界面等等。

676

2023.10.12

SQL中distinct的用法
SQL中distinct的用法

SQL中distinct的语法是“SELECT DISTINCT column1, column2,...,FROM table_name;”。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

320

2023.10.27

SQL中months_between使用方法
SQL中months_between使用方法

在SQL中,MONTHS_BETWEEN 是一个常见的函数,用于计算两个日期之间的月份差。想了解更多SQL的相关内容,可以阅读本专题下面的文章。

346

2024.02.23

SQL出现5120错误解决方法
SQL出现5120错误解决方法

SQL Server错误5120是由于没有足够的权限来访问或操作指定的数据库或文件引起的。想了解更多sql错误的相关内容,可以阅读本专题下面的文章。

1094

2024.03.06

sql procedure语法错误解决方法
sql procedure语法错误解决方法

sql procedure语法错误解决办法:1、仔细检查错误消息;2、检查语法规则;3、检查括号和引号;4、检查变量和参数;5、检查关键字和函数;6、逐步调试;7、参考文档和示例。想了解更多语法错误的相关内容,可以阅读本专题下面的文章。

357

2024.03.06

oracle数据库运行sql方法
oracle数据库运行sql方法

运行sql步骤包括:打开sql plus工具并连接到数据库。在提示符下输入sql语句。按enter键运行该语句。查看结果,错误消息或退出sql plus。想了解更多oracle数据库的相关内容,可以阅读本专题下面的文章。

675

2024.04.07

sql中where的含义
sql中where的含义

sql中where子句用于从表中过滤数据,它基于指定条件选择特定的行。想了解更多where的相关内容,可以阅读本专题下面的文章。

571

2024.04.29

sql中删除表的语句是什么
sql中删除表的语句是什么

sql中用于删除表的语句是drop table。语法为drop table table_name;该语句将永久删除指定表的表和数据。想了解更多sql的相关内容,可以阅读本专题下面的文章。

414

2024.04.29

c++主流开发框架汇总
c++主流开发框架汇总

本专题整合了c++开发框架推荐,阅读专题下面的文章了解更多详细内容。

77

2026.01.09

热门下载

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

精品课程

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

共48课时 | 1.7万人学习

MySQL 初学入门(mosh老师)
MySQL 初学入门(mosh老师)

共3课时 | 0.3万人学习

简单聊聊mysql8与网络通信
简单聊聊mysql8与网络通信

共1课时 | 785人学习

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

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号