【问题标题】:Migrating from using auto increment id to uuid with sequelize从使用自动增量 id 迁移到使用 sequelize 的 uuid
【发布时间】:2020-05-25 13:32:17
【问题描述】:

好的,我正在尝试一些不同的 ORM,目前正在开发 Sequelize。我已经定义了两个模型,asset 和asset_category,其中每个资产都有一个与asset_category 的外键关系。都好! 现在,我想从使用自动增量 id 更改为 uuid,因为它对安全性更好。所以我在数据库中有数据并编写了以下(超长!)迁移:

up: (queryInterface, Sequelize) => {
    return queryInterface
      .addColumn("asset_categories", "uuid", {
        // Add uuid column
        type: Sequelize.UUID,
        defaultValue: Sequelize.UUIDV4,
        allowNull: false,
      })
      .then(_ => {
        return queryInterface.sequelize.query(
          // Fill uuid column
          `
          UPDATE asset_categories SET uuid=uuid()
          `,
        );
      })
      .then(_ => {
        return queryInterface.addColumn("assets", "category_uuid", {
          // Add assets reference uuid column
          type: Sequelize.UUID,
          allowNull: false,
        });
      })
      .then(_ => {
        return queryInterface.sequelize.query(
          // Fill assets reference uuid column
          `
          UPDATE assets
          SET category_uuid= (SELECT ac.uuid FROM asset_categories ac WHERE ac.id = assets.category_id)
        `,
        );
      })
      .then(_ => {
        // Remove assets category_id column
        return queryInterface.removeColumn("assets", "category_id");
      })
      .then(_ => {
        // Remove asset_categories id column
        return queryInterface.removeColumn("asset_categories", "id");
      })
      .then(_ => {
        // Rename asset_categories uuid to id
        return queryInterface.renameColumn("asset_categories", "uuid", "id");
      })
      .then(_ => {
        // Rename assets category_uuid to category_id
        return queryInterface.renameColumn(
          "assets",
          "category_uuid",
          "category_id",
        );
      })
      .then(_ => {
        return queryInterface.changeColumn("asset_categories", "id", {
          // Add primary key to asset_categories id field
          type: Sequelize.UUID,
          defaultValue: Sequelize.UUIDV4,
          allowNull: false,
          primaryKey: true,
        });
      })
      .then(_ => {
        // Add index to asset_categories id field
        return queryInterface.addIndex("asset_categories", ["id"]);
      })
      .then(_ => {
        // Add index to assets category_id field
        return queryInterface.addIndex("assets", ["category_id"]);
      });

还有:

  up: (queryInterface, Sequelize) => {
    // Add uuid column
    return queryInterface
      .addColumn("assets", "uuid", {
        type: Sequelize.UUID,
        defaultValue: Sequelize.UUIDV4,
        allowNull: false,
        primaryKey: false,
      })
      .then(_ => {
        // Fill uuid column
        return queryInterface.sequelize.query(
          `
      UPDATE assets SET uuid=uuid()
      `,
        );
      })
      .then(_ => {
        // Remove assets id column
        return queryInterface.removeColumn("assets", "id");
      })
      .then(_ => {
        // Rename assets uuid to id
        return queryInterface.renameColumn("assets", "uuid", "id");
      })
      .then(_ => {
        // Add primary key to uuid column
        return queryInterface.changeColumn("assets", "id", {
          type: Sequelize.UUID,
          defaultValue: Sequelize.UUIDV4,
          allowNull: false,
          primaryKey: true,
        });
      })
      .then(_ => {
        // add foreign key on assets category_id
        return queryInterface.changeColumn("assets", "category_id", {
          type: Sequelize.UUID,
          allowNull: false,
          references: {
            model: {
              tableName: "asset_categories",
            },
            key: "id",
          },
        });
      });

问题是我在最后一步出现错误: ERROR: Referencing column 'category_id' and referenced column 'id' in foreign key constraint 'assets_ibfk_1' are incompatible.

似乎在所有这些步骤中,asset_category.id 更改为 id char(36) 字符集 utf8mb4 整理 utf8mb4_bin 非空,

虽然asset.category_id 是 category_id char(36) 整理 utf8mb4_general_ci 非空,

我假设这是我无法添加外键的原因,因为列不完全相同。

对于初学者:这是怎么发生的?是什么导致列获得不同的字符集或整理?还有:有没有更好的方法来处理这种迁移,因为与使用 Ruby on Rails + Active Record 相比,这似乎完全是垃圾......

【问题讨论】:

    标签: mysql node.js orm sequelize.js utf8mb4


    【解决方案1】:
    • DROP 涉及您将删除的 ids 的所有 FK。完成转换后为 uuid 添加 FK。
    • Uuid 应该是CHAR(36) CHARACTER SET ascii COLLATION ascii_general_ci
    • 如果您的表很大,您应该考虑转换为BINARY(16) 以节省大量磁盘空间。
    • 当前指向其他表中ids 的任何列也需要变为CHAR(36)...
    • 采取行动的顺序至关重要。

    类似:

    1. 备份整个数据集——下面的错误可能无法恢复。
    2. 删除 FK。在继续下一步之前对所有表执行此操作。
    3. 为每个类似 id 的列添加 COLUMN uuid;每个表中可能有多个。
    4. 使用新值填充将成为 PK 的 uuid。
    5. 通过基于现有 ID 执行多表 UPDATE 来填充其他 uuid。
    6. 更改客户端代码以引用 uuid;测试一下。
    7. 对于 PK 发生变化的表,DROP PRIMARY KEY 和 ADD PRIMARY KEY(uuid)。
    8. DROP COLUMN 用于 ids 和类似 id 的列。
    9. 在适当的情况下为 uuid 添加 FK。

    如果您选择使用较小的 uuid 格式,则会修改步骤 4、5、6 的详细信息。

    呃。

    【讨论】:

      猜你喜欢
      • 2012-11-16
      • 1970-01-01
      • 1970-01-01
      • 2015-03-06
      • 2017-05-18
      • 2023-02-15
      • 2018-11-05
      • 2016-02-19
      • 2020-03-10
      相关资源
      最近更新 更多