迁移回滚一定要写逆向操作吗?

Do I have to write the reverse operation for migration rollback?

我使用 knex.js,它是 PostgreSQL 的良好查询构建器。我还没有找到任何文档来解释如何以正确的方式进行迁移回滚。

目前我只是在down函数中写了反向迁移操作来做迁移回滚。这是正确的方法吗?

import * as Knex from 'knex';

exports.up = async (knex: Knex): Promise<any> => {
  await knex.schema.raw(`
    ALTER TABLE IF EXISTS "GOOGLE_CHANNEL" 
    ADD COLUMN IF NOT EXISTS google_channel_ad_group_cpc_bid INTEGER NOT NULL DEFAULT 0;
  `);

  await knex.schema.raw(`
    UPDATE "GOOGLE_CHANNEL" as gc
    SET
      google_channel_ad_group_cpc_bid = 7
    FROM "CAMPAIGN_TEMPLATE" as ct
    WHERE ct.campaign_channel_id = gc.campaign_channel_id;
  `);
};

exports.down = async (knex: Knex): Promise<any> => {
  // TODO: migration rollback
  await knex.schema.raw(``);
};

我有两个顾虑:

  1. 如果up函数中有很多SQL语句,我不得不在down中写很多SQL语句也可以运行以回滚迁移。

  2. 为什么knex.js不给我们写反向操作就做迁移回滚?我的意思是,knex.js 可以拍摄快照或记录数据库的保存点。

是的,要回滚,您可以使用迁移脚本的 down 功能。当您 运行 knex migrate:rollback 时,down 函数将 运行。 Knex 在数据库中有元 tables,用于确定哪些迁移有 运行 或没有。

例如:

exports.up = function (knex, Promise) {
  return knex.schema
    .createTable('role', function (table) {
      table.increments('role_id').primary();
      table.string('title').notNullable().unique();
      table.string('description');
      table.integer('level').notNullable(),
    })
    .createTable('user_account', function (table) {
      table.increments('user_id').primary();
      table.integer('role_id').references('role_id').inTable('role').notNullable();
      table.string('username').notNullable().unique();
      table.string('passwordHashed').notNullable();
      table.string('email', 50).notNullable().unique();
    });
};

exports.down = function (knex, Promise) {
  return knex.schema
    .dropTable('user_account')
    .dropTable('role');
};

这里我在up函数中创建了两个table。 user_account 有一个外键约束,并与 role table 链接,这意味着我必须在 [=15= 之前删除 user_account table ] table在向下函数中。

在你的例子中,你使用了更新语句。在向下函数中,您必须使用 hard-coded 值(迁移前的旧值)进行新更新,或者确保将旧值存储在历史记录中 table.

关于您的顾虑:

  1. 是的,如果你添加了很多东西,你也必须添加很多代码来反转你正在做的事情。但是,您可以跳过制作 down 脚本,但是您将无法回滚。一些(很多?)选择只前进而不回滚。如果他们必须修复某些问题,他们不会回滚,而是使用修复创建一个新的迁移脚本。

    我建议您在开始时创建向下功能。你可以考虑在适当的时候跳过制作它们。不降低功能的人通常必须在部署到生产环境之前在测试或暂存环境中更彻底地测试他们的迁移。这是为了确保它能正常工作,因为他们毕竟无法回滚。

  2. 我真的无法在这里为 Knex 创作者提供答案。但是,您所描述的潜在解决方案基本上是在迁移完成之前备份数据库。毕竟,迁移不仅仅是更改 table 等的布局。迁移脚本通常还会添加或删除新行。您可以使用备份方式,但您必须自己进行备份。

    Knex 是一个相当简单的查询生成器。如果您希望为您编写迁移脚本,您可能需要一个 full-blown OR 映射器。