事务提交后数据没变,大概率是提交了但被after/before触发器覆盖、innodb_flush_log_at_trx_commit非1导致未刷盘,或表引擎非innodb不支持事务。

检查是否有 AFTER UPDATE 触发器在偷偷改值
UPDATE 成功、COMMIT 也成功,但 SELECT 看到的还是旧值——最隐蔽的干扰源就是 AFTER UPDATE 触发器。它不报错、不改变 ROW_COUNT(),只在你眼皮底下把刚写进去的值又覆写一遍。
- 运行
SHOW TRIGGERS LIKE 'your_table_name';,重点看Timing列是否为AFTER - 查触发器定义:
SELECT ACTION_STATEMENT FROM information_schema.TRIGGERS WHERE EVENT_OBJECT_TABLE = 'your_table_name' AND EVENT_MANIPULATION = 'UPDATE' AND EVENT_TIMING = 'AFTER'; - 特别注意触发器体里有没有
NEW.col := ...这种赋值(注意是:=,不是=);如果写了NEW.status := OLD.status,那等于白更新 - 临时禁用验证:
ALTER TABLE your_table_name DISABLE TRIGGER trigger_name;(MySQL 8.0+),再试一次 UPDATE + COMMIT + SELECT
确认 innodb_flush_log_at_trx_commit 是否为 1
事务提交成功 ≠ 数据已落盘。如果 MySQL 配置了 innodb_flush_log_at_trx_commit = 0 或 2,崩溃或强制重启后,刚 COMMIT 的数据可能彻底丢失——你看到“没变化”,其实是压根没写进磁盘。
- 查当前值:
SHOW GLOBAL VARIABLES LIKE 'innodb_flush_log_at_trx_commit'; -
1:每次 COMMIT 都 fsync 到磁盘(安全,默认) -
0:log buffer 每秒刷一次,事务提交不刷盘(快但不安全) -
2:每次 COMMIT 写入 OS cache,但不 fsync(比 0 稍安全,仍可能丢) - 生产环境必须设为
1;若为0或2,且服务刚挂过,就解释得通“提交了却没变化”
验证表引擎是不是 InnoDB
用 START TRANSACTION 和 COMMIT 包裹了 SQL,结果还是立即生效、ROLLBACK 无效?大概率表是 MyISAM 引擎——它根本不支持事务,所有 DML 都自动提交,COMMIT 和 ROLLBACK 被静默忽略。
- 查引擎:
SHOW CREATE TABLE your_table_name;,看输出里有没有ENGINE=InnoDB - 或者查系统表:
SELECT ENGINE FROM information_schema.TABLES WHERE TABLE_SCHEMA = 'your_db' AND TABLE_NAME = 'your_table_name'; - 如果是
MyISAM,立刻转引擎:ALTER TABLE your_table_name ENGINE = InnoDB; - 注意:转换过程会锁表,大表需评估窗口期
别漏掉 BEFORE UPDATE 触发器的静默拦截
你以为 UPDATE 写进了新值,其实 BEFORE UPDATE 触发器早就把 NEW.col 改成了别的值,甚至还原成 OLD.col——你执行的是 UPDATE,数据库执行的是“SET NEW.x = OLD.x; THEN UPDATE”。表面看没报错,实则什么都没变。
- 查所有 UPDATE 触发器:
SELECT EVENT_TIMING, ACTION_STATEMENT FROM information_schema.TRIGGERS WHERE EVENT_OBJECT_TABLE = 'your_table_name' AND EVENT_MANIPULATION = 'UPDATE'; - 逐行检查
BEFORE触发器里是否有SET NEW.xxx = ...,尤其关注 IF 条件分支下的赋值 - 加调试输出(仅测试环境):
INSERT INTO debug_log(msg) VALUES (CONCAT('BEFORE: OLD.val=', OLD.val, ', NEW.val=', NEW.val)); - 这种问题不会报错,也不会影响
ROW_COUNT(),只能靠人工读触发器逻辑











