mysql - 使用sequelize从使用自动增量id迁移到uuid

标签 mysql node.js orm sequelize.js utf8mb4

好吧,我正在尝试一些不同的 ORM,目前正在研究 Sequelize。我定义了两个模型:asset 和 asset_category,其中每个 asset 都有与 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",
          },
        });
      });

问题是我在最后一步中遇到错误: 错误:引用列“category_id”和外键约束“assets_ibfk_1”中引用的列“id”不兼容。

似乎在所有这些步骤中 asset_category.id 更改为 id char(36) 字符集 utf8mb4 COLLATE utf8mb4_bin NOT NULL,

虽然 asset.category_id 是 category_id char(36) COLLATE utf8mb4_general_ci NOT NULL,

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

对于初学者来说:这是怎么发生的?是什么导致列获得不同的字符集或排序规则?另外:是否有更好的方法来实现这种迁移,因为与使用 Ruby on Rails + Active Record 相比,这看起来完全是垃圾......

最佳答案

  • DROP 涉及您要删除的 ids 的所有 FK。完成转换后为uuid添加FK。
  • Uuids 应为 CHAR(36) 字符集 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 用于 id 和类似 id 的列。
  9. 在适当的情况下为 uuid 添加 FK。

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

呃。

关于mysql - 使用sequelize从使用自动增量id迁移到uuid,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60146888/

相关文章:

php - 如何获得购物车相同用户ID的两个值的总和

c++ - 如何在 node.js 中使用用 c++ 编写的函数

mysql - 从名称为 MySQL 中另一个选择结果的列中选择

php多张照片上传和重命名

node.js - 如何使用云函数从 Firebase 查询特定数据

c++ - C++ 的 SQL 请求助手

java - 使用 ebean 或 hibernate 将值插入到一对一映射注释中

java - Hibernate缓存更新机制

mysql - 使用空间 MySQL 功能加速文本比较(特征向量)

javascript - 每当发生错误时 NodeJs 应用程序 "hanging"或 "freezing"