Skip to main content

数据库迁移

¥Database migrations

数据库迁移的目的是对数据库运行一次性查询,通常是在升级 Strapi 应用时修改表结构或数据。这些迁移会在应用启动时自动运行,并在 Strapi 启动时执行的自动模式迁移之前执行。

¥Database migrations exist to run one-time queries against the database, typically to modify the tables structure or the data when upgrading the Strapi application. These migrations are run automatically when the application starts and are executed before the automated schema migrations that Strapi also performs on boot.

🚧 实验特性

数据库迁移是实验性的。该功能仍在开发中,并将继续更新和改进。同时,请随时在 论坛 或社区 Discord 上寻求帮助。

¥Database migrations are experimental. This feature is still a work in progress and will continue to be updated and improved. In the meantime, feel free to ask for help on the forum or on the community Discord.

了解数据库迁移文件

¥Understanding database migration files

迁移是使用存储在 ./database/migrations 中的 JavaScript 迁移文件运行的。

¥Migrations are run using JavaScript migration files stored in ./database/migrations.

Strapi 会自动检测迁移文件,并在下次启动时按字母顺序运行一次。每个新文件都会执行一次。迁移在数据库表与内容类型架构同步之前运行。

¥Strapi automatically detects migration files and run them once at the next startup in alphabetical order. Every new file is executed once. Migrations are run before the database tables are synced with the content-types schemas.

⚠️ 警告
  • 目前 Strapi 不支持向下迁移。这意味着如果你需要恢复迁移,则必须手动执行。计划在未来实现向下迁移,但目前尚无时间表。

    ¥Currently Strapi does not support down migrations. This means that if you need to revert a migration, you will have to do it manually. It is planned to implement down migrations in the future but no timeline is currently available.

  • Strapi 将删除任何未知表而不发出警告。这意味着数据库迁移只能用于在更改 Strapi 架构时保留数据。forceMigrationrunMigrations 数据库配置参数 可用于微调数据库迁移行为。

    ¥Strapi will delete any unknown tables without warning. This means that database migrations can only be used to keep data when changing the Strapi schema. The forceMigration and runMigrations database configuration parameters can be used to fine-tune the database migrations behavior.

迁移文件应导出函数 up(),该函数在升级时使用(例如添加新表 my_new_table)。

¥Migration files should export the function up(), which is used when upgrading (e.g. adding a new table my_new_table).

up() 函数在数据库事务中运行,这意味着如果在迁移期间查询失败,则整个迁移将被取消,并且不会将任何更改应用于数据库。如果在迁移函数中创建另一个事务,它将充当嵌套事务。

¥The up() function runs in a database transaction which means if a query fails during the migration, the whole migration is cancelled, and no changes are applied to the database. If another transaction is created within the migration function, it will act as a nested transaction.

✏️ 注意

没有 CLI 可以手动执行数据库迁移。

¥There is no CLI to manually execute the database migrations.

创建迁移文件

¥Creating a migration file

创建迁移文件:

¥To create a migration file:

  1. ./database/migrations 文件夹中,创建一个以迁移日期和名称命名的新文件(例如 2022.05.10T00.00.00.name-of-my-migration.js)。确保文件名遵循此命名模式,因为文件的字母顺序定义了迁移必须运行的顺序。

    ¥In the ./database/migrations folder, create a new file named after the date and the name of the migration (e.g. 2022.05.10T00.00.00.name-of-my-migration.js). Make sure that the file name follows this naming pattern, because the alphabetical order of the files defines the order in which the migrations have to run.

  2. 将以下模板复制并粘贴到之前创建的文件中:

    ¥Copy and paste the following template in the previously created file:

'use strict'

async function up(knex) {}

module.exports = { up };
  1. 通过在 up() 函数内添加实际迁移代码来填充模板。up() 接收已处于事务状态的 Knex 实例,可用于运行数据库查询。

    ¥Fill in the template by adding actual migration code inside the up() function. up() receives a Knex instance, already in a transaction state, that can be used to run the database queries.

Example of migration file
./database/migrations/2022.05.10T00.00.00.name-of-my-migration.js

module.exports = {
async up(knex) {
// You have full access to the Knex.js API with an already initialized connection to the database

// Example: renaming a table
await knex.schema.renameTable('oldName', 'newName');

// Example: renaming a column
await knex.schema.table('someTable', table => {
table.renameColumn('oldName', 'newName');
});

// Example: updating data
await knex.from('someTable').update({ columnName: 'newValue' }).where({ columnName: 'oldValue' });
},
};

使用 Strapi 实例进行迁移

¥Using Strapi Instance for migrations

❗️ 危险

如果用户选择不直接使用 Knex 进行迁移,而是使用 Strapi 实例,则使用 strapi.db.transaction() 封装迁移代码非常重要。如果发生错误,则不这样做可能会导致迁移不会回滚。

¥If a user opts not to use Knex directly for migrations and instead utilizes the Strapi instance, it is important to wrap the migration code with strapi.db.transaction(). Failure to do so may result in migrations not rolling back if an error occurs.

Example of migration file with Strapi instance
./database/migrations/2022.05.10T00.00.00.name-of-my-migration.js
module.exports = {
async up() {
await strapi.db.transaction(async () => {
// Your migration code here

// Example: creating new entries
await strapi.entityService.create('api::article.article', {
data: {
title: 'My Article',
},
});

// Example: custom service method
await strapi.service('api::article.article').updateRelatedArticles();
});
},
};