【问题标题】:sequelize.js migration execution sequencesequelize.js 迁移执行顺序
【发布时间】:2019-08-12 05:40:50
【问题描述】:

我有几个要在同一次迁移中执行的查询。它们是相关的,因此必须按特定顺序执行。这是我迁移的 up 方法:

up: (queryInterface, Sequelize) =>
queryInterface.sequelize.transaction(transaction =>
  Promise.all([
    queryInterface.renameColumn(table, 'status', 'status_temp', { transaction }),
    queryInterface.sequelize.query(
      'ALTER TYPE enum_users_status RENAME TO enum_users_status_temp;',
      {
        transaction
      }
    ),
    queryInterface.addColumn(
      table,
      'isActive',
      {
        allowNull: false,
        defaultValue: false,
        type: Sequelize.BOOLEAN
      },
      { transaction }
    ),
    queryInterface.bulkUpdate(
      table,
      {
        isActive: true
      },
      {
        status: 'active'
      },
      { transaction }
    ),
    queryInterface.addColumn(
      table,
      'status',
      {
        allowNull: false,
        defaultValue: STATUS_FREE,
        type: Sequelize.ENUM(STATUS_FREE, STATUS_BUSY, STATUS_DELETED)
      },
      { transaction }
    ),
  ])
),

当我执行它时,订单以一种奇怪的方式混合在一起:

Executing (591dc838-4659-4de4-b605-54b7c03c527f): START TRANSACTION;
...
Executing (591dc838-4659-4de4-b605-54b7c03c527f): ALTER TYPE     enum_users_status RENAME TO enum_users_status_temp;
Executing (591dc838-4659-4de4-b605-54b7c03c527f): ALTER TABLE "public"."users" ADD COLUMN "isActive" BOOLEAN NOT NULL DEFAULT false;
Executing (591dc838-4659-4de4-b605-54b7c03c527f): UPDATE "users" SET "isActive"=true WHERE "status" = 'active'
Executing (591dc838-4659-4de4-b605-54b7c03c527f): CREATE TYPE "public"."enum_users_status" AS ENUM('free', 'busy', 'deleted');ALTER TABLE "public"."users" ADD COLUMN "status" "public"."enum_users_status" NOT NULL DEFAULT 'free';
Executing (591dc838-4659-4de4-b605-54b7c03c527f): ALTER TABLE "users" RENAME COLUMN "status" TO "status_temp";
Executing (591dc838-4659-4de4-b605-54b7c03c527f): ROLLBACK;

因此我遇到了错误:

ERROR: column "status" of relation "users" already exists

有没有办法让这些查询按特定顺序运行?

更新: 我的预期结果是这样的

      START TRANSACTION;
      ALTER TABLE "users" RENAME COLUMN "status" TO "status_temp";
      ALTER TYPE enum_users_status RENAME TO enum_users_status_temp;
      ALTER TABLE "public"."users" ADD COLUMN "isNew" BOOLEAN NOT NULL DEFAULT true;
      UPDATE "users" SET "isNew"=false WHERE "status_temp" = 'active';
      CREATE TYPE "public"."enum_users_status" AS ENUM('free', 'busy', 'deleted');
      ALTER TABLE "public"."users" ADD COLUMN "status" "public"."enum_users_status" NOT NULL DEFAULT 'free';
      UPDATE "users" SET "status"='busy' WHERE "isFree" = false;
      UPDATE "users" SET "status"='deleted' WHERE "status_temp" = 'deleted';
      ALTER TABLE "public"."users" DROP COLUMN "isFree";
      ALTER TABLE "public"."users" DROP COLUMN "status_temp";

【问题讨论】:

    标签: sequelize.js sequelize-cli


    【解决方案1】:

    发生这种情况是因为您正在使用 Promise.all 并行执行承诺。无法保证您的承诺将按照他们定义的顺序执行。所以你需要使用.then 方法来执行你的工作流。

    up: (queryInterface, Sequelize) =>
    queryInterface.sequelize.transaction(transaction =>
      queryInterface.renameColumn(table, 'status', 'status_temp', { transaction })
        .then(() => queryInterface.sequelize.query(
          'ALTER TYPE enum_users_status RENAME TO enum_users_status_temp;',
          {
            transaction
          }
        ))
        .then(...);
    ),
    

    【讨论】:

    • 是否可以简单地让它们按照我编写它们的顺序在一个事务中查询,而没有这些丑陋的 then() 重复?
    • 我不明白 then() 有什么问题?如果你不喜欢 then() 就使用 async/await
    • 你不能像你的例子那样使用事务
    • 为什么?没有区别,只是执行顺序
    【解决方案2】:

    正如 Eugene 指出的那样,您的问题是您使用 Promise.all 调用所有迁移。我强烈建议做单独的迁移文件。这样,您的项目结构就会更好,并且更容易被新开发人员理解。

    创建迁移的命令:

    sequelize migration:generate --name [name-of-your-migration]
    

    按创建顺序执行所有迁移以及尚未运行的迁移:

    sequelize db:migrate
    

    【讨论】:

    • 谢谢。但我不确定这是否是个好主意。我想将所有逻辑相关的查询放在一个文件中。此示例已过时,但我需要: 1. 再创建 1 个字段 2. 删除一个现有字段 3. 更改状态字段 PS:所有这些字段中的数据都应从以前版本的字段迁移,这就是为什么我把它全部一起 + 因为迁移都在同一个文件夹中,我认为制作额外内容不是一个好主意
    【解决方案3】:

    可以使用 bluebirdjs Promise.map 函数和 {concurrency: 1} 选项,如下所示:

    const Promise = require('bluebird');
    ...
    
    up: function (queryInterface, Sequelize) {
        return Promise.map([
                queryInterface.sequelize.query('SET FOREIGN_KEY_CHECKS = 0'),
                queryInterface.addColumn(
                    'table1',
                    'column1',
                    {
                        type: Sequelize.INTEGER,
                        after: 'id',
                        defaultValue: 0
                    }),
                queryInterface.sequelize.query('SET FOREIGN_KEY_CHECKS = 1'),
                queryInterface.addColumn(
                    'table2',
                    'column2',
                    {
                        type: Sequelize.BOOLEAN,
                        after: 'column3',
                        defaultValue: 0
                    })
            ],
            (promise) => promise,
            {concurrency: 1}
        );
    }
    

    注意:您可以将concurrency 选项设置为n 以同时执行n 承诺

    【讨论】:

      猜你喜欢
      • 2016-01-30
      • 2015-10-09
      • 2017-11-24
      • 1970-01-01
      • 1970-01-01
      • 2014-08-14
      • 1970-01-01
      • 2014-02-02
      • 2020-04-20
      相关资源
      最近更新 更多