TypeORM迁移失败时ROLLBACK未执行down()函数问题咨询
TypeORM迁移失败后事务未回滚已创建表的原因及解决办法
问题核心原因
你遇到的问题本质是MySQL对DDL语句的原生处理规则导致的:
MySQL的InnoDB引擎虽然支持事务,但所有DDL操作(比如CREATE TABLE、DROP TABLE)执行时会隐式提交当前事务。也就是说,当你在迁移的up()方法里执行完CREATE TABLE users3这条语句时,数据库已经自动提交了这个操作,users3表被永久创建。后续创建users4报错触发ROLLBACK时,只能回滚未提交的事务内容,而已经被隐式提交的users3表不会被撤销。
TypeORM确实会将迁移逻辑包裹在事务中,但MySQL的DDL隐式提交规则直接绕过了这个机制,这和TypeORM本身的实现无关。
解决步骤
手动清理残留表
登录数据库执行DROP TABLE users3;,先移除已经创建的表,再重新运行修复后的迁移命令。修复字段类型错误
float(100)是不合法的MySQL字段定义,float类型的精度参数格式为(总位数, 小数位数),总位数最大为53。可以改成合法格式比如float(10,2),或者直接使用double类型替代:CREATE TABLE `users4` ( `id` int NOT NULL AUTO_INCREMENT, `value` float(10,2) NOT NULL, -- 修正后的字段定义 PRIMARY KEY (`id`) ) ENGINE = InnoDB优化迁移的原子性
- 将可能出错的DDL操作放在迁移逻辑的最前面:如果前面的操作失败,后面的表不会被创建,减少残留数据的概率。
- 给DDL语句添加
IF NOT EXISTS/IF EXISTS判断,避免重复操作报错:CREATE TABLE IF NOT EXISTS `users3` (...)
修复后的迁移代码示例
public async up(queryRunner: QueryRunner): Promise<void> { // 先创建可能出错的users4(已修复字段类型) await queryRunner.query(` CREATE TABLE \`users4\` ( \`id\` int NOT NULL AUTO_INCREMENT, \`value\` float(10,2) NOT NULL, PRIMARY KEY (\`id\`) ) ENGINE = InnoDB `); // 再创建users3 await queryRunner.query(` CREATE TABLE \`users3\` ( \`id\` int NOT NULL AUTO_INCREMENT, \`username\` varchar(255) NOT NULL, PRIMARY KEY (\`id\`) ) ENGINE = InnoDB `); } public async down(queryRunner: QueryRunner): Promise<void> { await queryRunner.query(`DROP TABLE IF EXISTS \`users4\``); await queryRunner.query(`DROP TABLE IF EXISTS \`users3\``); }
内容的提问来源于stack exchange,提问作者Abdallah
相关产品推荐
相关产品推荐

