You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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本身的实现无关。

解决步骤

  1. 手动清理残留表
    登录数据库执行DROP TABLE users3;,先移除已经创建的表,再重新运行修复后的迁移命令。

  2. 修复字段类型错误
    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
    
  3. 优化迁移的原子性

    • 将可能出错的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 19:22:50