MySQL事务仅InnoDB引擎支持,MyISAM不支持;外键需配合事务才能保证数据一致性;DDL会隐式提交事务;SET FOREIGN_KEY_CHECKS=0危险且不跨会话。

MySQL 事务必须用 InnoDB 引擎才生效
MyISAM 不支持事务,哪怕写了 BEGIN 或 START TRANSACTION,提交或回滚都无效。检查表引擎用:
SHOW CREATE TABLE `order`;如果看到
ENGINE=MyISAM,就得改:ALTER TABLE `order` ENGINE = InnoDB;注意:改引擎会锁表,大表慎操作;同时确保 MySQL 配置没禁用 InnoDB(
skip-innodb 已废弃,但旧配置可能残留)。
外键约束依赖事务才能真正防脏写
外键本身只拦住显式违反参照的动作(比如插入不存在的 user_id),但若没包在事务里,多步操作仍可能中间态不一致。例如先删用户、再删其订单,中间若崩了,就剩孤儿订单。正确做法是:
BEGIN; DELETE FROM `user` WHERE id = 123; DELETE FROM `order` WHERE user_id = 123; COMMIT;此时外键 + 事务共同保证“全成功或全失败”。另外,外键定义时要明确
ON DELETE CASCADE 或 ON DELETE RESTRICT,否则默认是 RESTRICT,删父记录会直接报错 Cannot delete or update a parent row。
事务中执行 DDL(如 ALTER)会隐式提交
在事务里执行 ALTER TABLE、DROP INDEX 等 DDL 语句,MySQL 会自动触发 COMMIT,导致前面所有 DML 不可回滚。常见踩坑场景:
BEGIN;
INSERT INTO `log` VALUES ('start');
ALTER TABLE `order` ADD COLUMN status TINYINT DEFAULT 0;
INSERT INTO `log` VALUES ('done'); -- 这条即使后面 ROLLBACK,前面 INSERT 也已提交
ROLLBACK;结果 log 表里仍有 'start'。解决办法:DDL 单独执行,或改用支持事务 DDL 的 MySQL 8.0+(但仅限部分操作,且需确认 innodb_ddl_log_enabled=ON)。
SET FOREIGN_KEY_CHECKS=0 是危险开关
临时关外键检查(SET FOREIGN_KEY_CHECKS=0)常用于导入数据或修复,但它绕过所有外键约束,事务也无法挽救。一旦关了又忘了开,后续所有写入都可能造出脏数据。更隐蔽的问题是:它**不跨会话**,所以脚本里设了却没重连,新连接仍是开启状态;但若在长连接中设为 0 后异常退出,下次复用该连接时仍为 0。建议:
- 只在必要时临时关闭,且紧跟着
SET FOREIGN_KEY_CHECKS=1 - 避免在应用层代码里动态开关,优先用
DISABLE KEYS配合LOAD DATA INFILE - 监控 SQL 日志,搜
FOREIGN_KEY_CHECKS=0出现频次










