mysql中使用事务与外键保证数据一致性

来源:这里教程网 时间:2026-02-28 20:44:25 作者:

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
出现频次

相关推荐