MySQL导入SQL文件时如何实现单条插入失败则整体回滚?
MySQL 整份SQL文件原子导入(全成/全回滚)实现方法
首先确认前置要求:你要导入的目标表必须使用支持事务的存储引擎(比如InnoDB),MyISAM这类不支持事务的引擎无法实现回滚,这个是硬前提。
具体操作步骤
1. 修改生成的import.sql文件结构
在文件最开头加以下配置语句,关闭自动提交、开启事务:
SET autocommit=0; START TRANSACTION; -- 开启严格模式,避免隐式转换导致的静默失败 SET @@SESSION.sql_mode = 'STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION';
中间保留你生成的所有INSERT语句即可,不需要额外改动。
在文件最末尾,也就是所有INSERT语句的最后,加事务提交语句:
COMMIT;
2. 调整导入命令,保证出错立刻终止
你原来的导入命令缺少出错终止的配置,遇到错误会跳过错误语句继续执行后面的内容,甚至可能执行到最后的COMMIT,导致部分数据入库。把命令改成下面这样:
mysql -u user -p --abort-source-on-error dbase < import.sql
--abort-source-on-error是MySQL客户端自带参数,作用是执行SQL文件时只要遇到任意报错,立刻终止整个脚本的执行,不会继续跑后续语句。
生效逻辑说明
所有INSERT语句会在同一个未提交的事务中执行,这些修改在执行COMMIT之前不会持久化到磁盘,仅当前会话可见。
只要任意一条INSERT执行失败,客户端会立刻终止执行并断开数据库连接,MySQL服务端检测到会话断开后,会自动回滚该会话所有未提交的改动,相当于整份文件的操作全部撤销。
只有所有INSERT全部执行成功,脚本才会走到最后一行的COMMIT,所有改动才会一次性持久化生效,完全满足全成功才提交、任意失败全回滚的需求。
注意避坑
- 不要在INSERT语句段里手动加
COMMIT/ROLLBACK/START TRANSACTION语句,会把整个大事务拆碎,无法实现整体回滚 - 不要给导入命令加
--force参数,这个参数的作用是强制跳过错误继续执行,和需求完全相反 - 几十万条INSERT属于中等规模事务,提前确认MySQL的undo表空间有足够剩余,避免因空间不足导致事务回滚
- 导入过程中会持有插入数据的行锁,尽量不要在导入时从其他会话修改同表数据,避免触发锁等待
- 如果你用的是MySQL 5.6及更早的版本,客户端没有
--abort-source-on-error参数,可以先登录MySQL交互终端,执行source import.sql导入,交互模式下默认遇到SQL错误就会终止执行,不会继续跑后续语句,效果一致。
内容的提问来源于stack exchange,提问作者karozans
相关产品推荐
相关产品推荐

