- 后端
【免费下载链接】mikro-orm
TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, MariaDB, MS SQL Server, PostgreSQL and SQLite/libSQL databases.
MikroORM 内置了基于 Schema 差异(schema diff)的迁移系统:它根据当前实体元数据与目标数据库 schema 之间的差异自动生成迁移文件,并支持事务包裹、执行日志表、schema 快照比对以及面向多租户场景的运行时 schema 上下文(runtime schema context)。本文以@mikro-orm/migrations(SQL 驱动)与@mikro-orm/migrations-mongodb(MongoDB)两个扩展包为主线,完整覆盖迁移类编写、初始迁移、快照机制、全部配置项、CLI 与编程式用法、自定义生成器及调试手段,并辅以本仓库 packages/migrations 与 packages/migrations-mongodb 的源码实现佐证,帮助你把这套迁移体系真正落地到开发、测试与生产环境。
认识迁移系统:扩展注册与核心机制
MikroORM 的迁移能力通过扩展(extension)注入,使用前需要安装对应驱动类型的迁移包,并在 ORM 配置中注册Migrator:
import { Migrator } from '@mikro-orm/migrations'; // 或 `@mikro-orm/migrations-mongodb` export default defineConfig({ // ... extensions: [Migrator], })- SQL 驱动(PostgreSQL、MySQL、MariaDB、MSSQL、SQLite/libSQL 等)使用
@mikro-orm/migrations; - MongoDB 使用独立的
@mikro-orm/migrations-mongodb。
注册后,orm.migrator便可用(其实现位于 packages/migrations/src/Migrator.ts,继承自 core 包中的 AbstractMigrator,register()方法把 migrator 注册为 ORM 扩展)。
几个贯穿全文的基础事实:
- 迁移文件不携带扩展名存储:
MigrationStorage在读写执行日志时通过getMigrationName()去掉.js/.ts后缀(见 MigrationStorage.ts),因此同一迁移在 TS 源码与编译产物之间共享同一个记录名。 - 默认事务包裹:每条迁移默认在独立事务中执行,且整批迁移会被包裹进一个主事务(master transaction)。任一迁移失败,整批全部回滚。这由
MigrationRunner实现:非事务模式直接串行执行查询,事务模式则通过connection.transactional()并以ctx: this.#masterTransaction汇入主事务(见 MigrationRunner.ts)。 - 执行日志表:默认表名为
mikro_orm_migrations,包含id(自增主键)、name、executed_at三列,由MigrationStorage.ensureTable()按需创建(见 MigrationStorage.ts)。
编写第一个迁移:Migration 类
迁移是继承抽象类Migration的类,实现up()方法,可选择性实现down():
import { Migration } from '@mikro-orm/migrations'; export class Migration20191019195930 extends Migration { async up(): Promise<void> { this.addSql('select 1 + 1'); } }要点:
down()默认抛错(This migration cannot be reverted,见 Migration.ts),只有显式实现down()的迁移才支持回滚。isTransactional(): boolean默认返回true,可在单个迁移上覆写,实现"这条迁移不进事务"的定制行为(Migration.ts)。Configuration对象与驱动实例在Migration类上下文中可用——基类构造器即接收driver与config(Migration.ts)。this.execute(sql, params?)直接执行原生 SQL,且与迁移的其余查询共享同一事务上下文ctx(Migration.ts)。this.addSql()除字符串外还接受NativeQueryBuilder(原生查询构建器)实例或raw()SQL 片段(Query联合类型定义于 Migration.ts)。
在迁移中使用 EntityManager
迁移的主要职责是修改 SQL schema,但也可用于数据修改,方式有二:this.execute()原生 SQL,或通过 EntityManager:
import { Migration } from '@mikro-orm/migrations'; import { User } from '../entities/User'; export class Migration20191019195930 extends Migration { async up(): Promise<void> { const em = this.getEntityManager(); em.create(User, { ... }); await em.flush(); } }:::warning 在迁移中使用EntityManager是可行的,但不推荐:它依赖"当前检出代码"的实体元数据,而非生成迁移那一刻的状态,一旦元数据随时间演进,旧迁移可能出错。优先在迁移中使用原生查询。 :::
getEntityManager()返回一个缓存且已绑定当前事务上下文的 EM 实例(setTransactionContext(this.ctx)),源码见 Migration.ts。
初始迁移:实体与 schema 均已存在时
当项目已经有现成数据库 schema,想引入迁移体系时,用--initial创建初始迁移:
npx mikro-orm migration:create --initial约束与行为:
- 仅当此前从未生成或执行过任何迁移时可用;
Migrator.validateInitialMigration()会先检查 executed 与 pending 列表,非空即抛错(Migrator.ts)。 - 初始迁移内容等价于
schema:create的 schema 转储(即getCreateSchemaSQL()的完整建表脚本,见 Migrator.ts)。 - 若数据库已存在实体对应的全部表,迁移会被自动标记为已执行(
storage.logMigration,见 Migrator.ts);若只存在部分表则抛错,提示先清理这些表。
快照机制:基于目标 Schema 而非数据库
创建新迁移时,系统会把目标 schema 快照自动保存到迁移文件夹中。之后创建迁移时以该快照为 diff 基准,而不是实时读取数据库——这意味着即使你还没执行 pending 迁移,也能生成正确的 schema 差异。
快照文件由两条不同来源写入:
migration:create(及--initial):由实体元数据推导的目标 schema(storeCurrentSchema()默认取getTargetSchema());migration:up/migration:down:迁移应用后,通过数据库 introspection 重写快照(Migrator.ts)。
两条路径对同一 schema 产生相同的序列化形态,因此migration:create之后执行迁移通常不会产生有意义的快照重写;但部分数据库特有的细节(如 PostgreSQL 的int与int4类型别名)仍可能产生细微 diff。runMigrations()中有一个细节值得注意:若 introspection 结果与现有快照在SchemaComparator语义上一致,则跳过重写,避免把表达式大小写、索引方法等"外观噪声"写进 diff(Migrator.ts)。
- 快照文件应像迁移文件一样纳入版本控制(默认命名为
.snapshot-<dbName>.json,可由snapshotName覆盖,路径解析见 Migrator.ts)。 - 通过
migrations.snapshot: false可关闭快照。 - 若希望快照只描述实体元数据,设
migrations.snapshotOnMigrate: false,跳过migration:up/migration:down的 introspection 重写。注意:关闭后快照不再跟随数据库,migration:down之后执行migration:create仍会对比回滚前的状态,产生空 diff;此时应改用migration:up重新应用既有迁移,而不是重新生成。
配置详解
pattern选项已被glob取代;migrations.path与migrations.pathTs的工作方式与实体发现中的entities/entitiesTs一致(后者存在时优先于前者,见 Migrator.ts 中快照路径的解析逻辑)。
await MikroORM.init({ // 默认值: migrations: { tableName: 'mikro_orm_migrations', path: './migrations', pathTs: undefined, glob: '!(*.d).{js,ts,cjs}', silent: false, transactional: true, disableForeignKeys: false, allOrNothing: true, dropTables: true, safe: false, snapshot: true, snapshotOnMigrate: true, emit: 'ts', generator: TSMigrationGenerator, fileName: (timestamp: string, name?: string) => `Migration${timestamp}${name ? '_' + name : ''}`, }, })以上默认值与 packages/core/src/utils/Configuration.ts 中MigrationsOptions的类型定义一一对应,可按需覆写。
可用选项速查表
| 选项 | 说明 |
|---|---|
tableName: string | 存储迁移执行日志的数据库表名,默认'mikro_orm_migrations'。也支持schema.tableName形式(MigrationStorage.resolveTableName()会解析出 schema 部分,见 MigrationStorage.ts)。 |
path: string | 存放编译后迁移文件的目录,默认'./migrations',生产环境应指向 JS 文件。 |
pathTs: string | 存放 TypeScript 迁移源码的目录,开发期配合tsx等使用;若指定,path应指向编译输出。 |
glob: string | 匹配迁移文件的 glob,默认'!(*.d).{js,ts,cjs}'(匹配除.d.ts外的全部.js/.ts/.cjs)。 |
silent: boolean | 是否抑制迁移执行日志,默认false。 |
transactional: boolean | 是否将每条迁移包裹在事务中,默认true。设为false时迁移不再自动进入事务。 |
disableForeignKeys: boolean | 迁移期间是否禁用外键检查,默认false。为true时会在语句前后包裹set foreign_key_checks = 0等价的开启/恢复语句(由SchemaHelper.getSchemaBeginning/getSchemaEnd拼接,见 MigrationRunner.ts)。 |
allOrNothing: boolean | 是否把所有迁移包进一个主事务,默认true;任一迁移失败则全部回滚。 |
dropTables: boolean | 是否允许在迁移中删表,默认true;为false时跳过删表操作。 |
safe: boolean | 安全模式,默认false;为true时同时禁用删表与删列。 |
snapshot: boolean | 创建新迁移时是否保存 schema 快照,默认true。快照辅助 diff,应随迁移文件一起纳入版本控制。 |
snapshotOnMigrate: boolean | 执行迁移时是否从数据库 introspection 更新快照,默认true;设为false后快照仅由migration:create管理。 |
snapshotName: string | 快照文件自定义名称,默认基于迁移时间戳生成。 |
emit: 'js' \| 'ts' \| 'cjs' | 生成迁移文件的格式,默认'ts'。emit还会决定使用TSMigrationGenerator还是JSMigrationGenerator(见 Migrator.ts)。 |
generator: Constructor<IMigrationGenerator> | 生成迁移文件内容的生成器类,默认TSMigrationGenerator,可自定义格式化与结构。 |
fileName: (timestamp: string, name?: string) => string | 迁移文件名生成函数,接收时间戳与可选名称,默认Migration${timestamp}${name ? '_' + name : ''}。 |
migrationsList: (MigrationObject \| Constructor<Migration>)[] | 迁移对象/类数组,替代基于文件系统的发现机制,适合打包(bundled)场景。 |
schema: string | 运行迁移的目标 schema。设置后,每条迁移前会执行驱动的 "set current schema" 语句,跟踪表也位于该 schema。参见下方「运行时 schema 上下文」。MSSQL 不支持。 |
includeWildcardSchema: boolean | 为true时,schema: '*'的实体被纳入migration:create输出,并生成不带限定符的 DDL,从而可经由migrator.up({ schema })应用于任意 schema,默认false。 |
示例配置
await MikroORM.init({ migrations: { tableName: 'my_migrations', path: 'dist/migrations', pathTs: 'src/migrations', glob: '*.{js,ts}', silent: false, transactional: true, disableForeignKeys: true, allOrNothing: true, dropTables: false, // 出于安全禁用删表 safe: false, snapshot: true, emit: 'ts', fileName: (timestamp, name) => `${timestamp}_${name || 'migration'}`, }, });环境变量覆盖
上述选项也可通过环境变量覆盖(机制见 docs/versioned_docs/version-7.2/configuration.md#using-environment-variables):
MIKRO_ORM_MIGRATIONS_TABLE_NAMEMIKRO_ORM_MIGRATIONS_PATHMIKRO_ORM_MIGRATIONS_PATH_TSMIKRO_ORM_MIGRATIONS_GLOBMIKRO_ORM_MIGRATIONS_TRANSACTIONALMIKRO_ORM_MIGRATIONS_DISABLE_FOREIGN_KEYSMIKRO_ORM_MIGRATIONS_ALL_OR_NOTHINGMIKRO_ORM_MIGRATIONS_DROP_TABLESMIKRO_ORM_MIGRATIONS_SAFEMIKRO_ORM_MIGRATIONS_SILENTMIKRO_ORM_MIGRATIONS_EMITMIKRO_ORM_MIGRATIONS_SNAPSHOTMIKRO_ORM_MIGRATIONS_SNAPSHOT_ON_MIGRATEMIKRO_ORM_MIGRATIONS_SNAPSHOT_NAME
在生产环境运行迁移
生产环境应使用编译后的迁移文件,几乎开箱即用,只需正确配置路径:
import { MikroORM, Utils } from '@mikro-orm/core'; await MikroORM.init({ migrations: { path: 'dist/migrations', pathTs: 'src/migrations', }, // 或二选一: // migrations: { // path: Utils.detectTypeScriptSupport() ? 'src/migrations' : 'dist/migrations', // }, // ... });这样在 CLI 中(通常开启 TS 支持)生成 TS 迁移文件,而在生产环境使用编译后的 JS 文件。MigrationGenerator.generate()会按emit选项在pathTs与path之间选择输出目录,并以baseDir为基准做路径归一化与目录创建(MigrationGenerator.ts)。
使用自定义 MigrationGenerator
生成新迁移时,MigrationGenerator负责产出文件内容,你可以提供自己的实现来做 SQL 格式化等定制:
import { TSMigrationGenerator } from '@mikro-orm/migrations'; import { format } from 'sql-formatter'; class CustomMigrationGenerator extends TSMigrationGenerator { generateMigrationFile(className: string, diff: { up: string[]; down: string[] }): string { const comment = '// this file was generated via custom migration generator\n\n'; return comment + super.generateMigrationFile(className, diff); } createStatement(sql: string, padLeft: number): string { sql = format(sql, { language: 'postgresql' }); // 一点缩进魔法 sql = sql.split('\n').map((l, i) => i === 0 ? l : `${' '.repeat(padLeft + 13)}${l}`).join('\n'); return super.createStatement(sql, padLeft); } } await MikroORM.init({ // ... migrations: { generator: CustomMigrationGenerator, }, });生成器基类MigrationGenerator会生成形如Migration20230421212713的类名(时间戳来自new Date().toISOString().replace(/[-T:]|\.\d{3}z$/gi, ''),见 MigrationGenerator.ts),而默认的 TSMigrationGenerator 产出的文件会自动带上override name = '...'与up()/down()骨架;createStatement会对 SQL 中的反引号、$、反斜杠做转义后包进this.addSql(\...`)`。
使用 CLI 管理迁移
npx mikro-orm migration:create # 用当前 schema 差异创建新迁移 npx mikro-orm migration:up # 迁移到最新版本 npx mikro-orm migration:down # 向下迁移一步 npx mikro-orm migration:list # 列出所有已执行的迁移 npx mikro-orm migration:check # 检查 schema 是否最新 npx mikro-orm migration:pending # 列出所有待执行的迁移 npx mikro-orm migration:fresh # 删除数据库并迁移到最新版本 npx mikro-orm migration:log # 将迁移标记为已执行但不运行 npx mikro-orm migration:unlog # 从已执行列表移除迁移但不回滚 npx mikro-orm migration:rollup # 将所有已执行迁移合并为单个迁移创建空白迁移文件可用
npx mikro-orm migration:create --blank(生成的up()/down()为占位的select 1,见 Migrator.ts)。
migration:up与migration:down支持--from(-f)、--to(-t)、--only(-o)选项,只运行迁移的子集:
npx mikro-orm migration:up --from 2019101911 --to 2019102117 # 同上 npx mikro-orm migration:up --only 2019101923 # 只应用单个迁移 npx mikro-orm migration:down --to 0 # 向下回滚所有迁移运行 TS 迁移文件时请确保项目安装了
tsx,CLI 会自动使用它。
migration:fresh支持--seed在迁移后播种数据:
npx mikro-orm migration:fresh --seed # 使用默认 seeder 播种 npx mikro-orm migration:fresh --seed=UsersSeeder # 使用 UsersSeeder 播种默认 seeder 可在 orm 配置中用
config.seeder.defaultSeeder指定。
migration:rollup会把所有已执行迁移合并为一个迁移文件,适合清理长期积累的大量迁移。它通过抽取每个迁移up()/down()方法中的源码并拼接成新文件实现——除更新迁移日志外不触碰数据库,因此没有数据丢失风险。CLI 侧的参数解析与分发位于 packages/cli/src/commands/MigrationCommandFactory.ts。
编程式使用 Migrator
也可以在脚本中直接初始化 MikroORM 并调用orm.migrator:
import { MikroORM } from '@mikro-orm/core'; import { Migrator } from '@mikro-orm/migrations'; (async () => { const orm = await MikroORM.init({ extensions: [Migrator], dbName: 'your-db-name', // ... }); await orm.migrator.create(); // 创建文件 Migration20191019195930.ts await orm.migrator.up(); // 迁移到最新 await orm.migrator.up('name'); // 只向上运行指定迁移 await orm.migrator.up({ to: 'up-to-name' }); // 迁移到指定版本 await orm.migrator.down(); // 向下迁移一步 await orm.migrator.down('name'); // 只向下运行指定迁移 await orm.migrator.down({ to: 'down-to-name' }); // 向下迁移到指定版本 await orm.migrator.down({ to: 0 }); // 回滚到第一个版本 await orm.migrator.rollup(); // 把所有已执行迁移合并为一个 await orm.migrator.rollup(['Migration1', 'Migration2']); // 合并指定迁移 await orm.migrator.up({ schema: 'tenant_42' }); // 针对特定 schema 运行,见"运行时 schema 上下文" await orm.close(true); })();然后用tsx运行(或编译为纯 JS 后使用node):
$ tsx migratecreate()返回{ fileName, code, diff };当 diff 为空时返回空文件名与空代码(Migrator.ts)。getPending()在快照存在时会走快照路径:数据库不可达时把发现的迁移全部视为 pending(Migrator.ts)。
提供事务上下文
某些场景下你可能想自己控制事务上下文:
await orm.em.transactional(async em => { await migrator.up({ transaction: em.getTransactionContext() }); });AbstractMigrator的MigrateOptions支持from/to/migrations/transaction/schema五个维度(见 AbstractMigrator.ts),to归一化后既可以是迁移名也可以是0(回滚全部)。
运行时 schema 上下文:一套迁移、多个 Schema
默认情况下,迁移针对 SQL 中烘焙的 schema(无限定符的 DDL 则针对连接默认 schema)运行。运行时 schema 上下文允许你把既有迁移重定向到另一个 schema 而无需重新生成——适合"每部署一个 schema"(如 PR 预览环境),以及把同一套迁移扩散到多个租户 schema。
解析到运行时 schema 时,migrator 会在每条迁移前插入驱动的 "set current schema" 语句,并在finally中复位(resetSessionSchema,见 MigrationRunner.ts),避免连接池中的连接滞留在迁移目标 schema。迁移跟踪表跟随同一 schema,因此每个目标都拥有独立的迁移历史(MigrationStorage的resolveTableName()优先取#runSchema,见 MigrationStorage.ts)。
| 驱动 | Set | Reset |
|---|---|---|
| PostgreSQL | SET search_path TO "x" | RESET search_path |
| MySQL / MariaDB | USE `x` | USE `<config.dbName>` |
| Oracle | ALTER SESSION SET CURRENT_SCHEMA = "x" | ALTER SESSION SET CURRENT_SCHEMA = "<dbName>" |
| MSSQL | 不支持——抛错 | — |
| SQLite / libSQL | 无 schema 概念——静默无操作 | — |
每部署一个 schema
在 ORM 配置中设置migrations.schema,既有无限定符迁移即在指定 schema 中执行,跟踪表同在:
await MikroORM.init({ migrations: { schema: process.env.PR_PREVIEW_SCHEMA, // 例如 'pr_1234' }, });多租户扩散
通过migrations.includeWildcardSchema把通配符实体纳入migration:create,再用migrator.up({ schema })应用生成的无限定符迁移:
await MikroORM.init({ migrations: { includeWildcardSchema: true, }, }); for (const tenant of tenants) { await orm.migrator.up({ schema: tenant }); }不修改全局配置也能查看单个租户的迁移状态:
await orm.migrator.getExecuted({ schema: 'tenant_42' }); await orm.migrator.getPending({ schema: 'tenant_42' });租户编排与失败恢复由调用方负责——migrator 暴露的是按 schema 的原语,而非托管的多租户运行器。
:::caution 要让migration:create生成无限定符 DDL,生成迁移时既不能设置options.schema,也不能设置config.schema。若设置了config.schema,通配符表会被加上该 schema 限定(本地开发时有用)。请在没有config.schema的环境中生成迁移,再以migrator.up({ schema })应用。 :::
CLI 支持
migration:up与migration:down都接受--schema(别名-s)标志:
npx mikro-orm migration:up --schema tenant_42 npx mikro-orm migration:down --schema tenant_42注意事项
public并非隐式可用:search_path(或等价物)只指向目标 schema——引用public中的扩展或共享查询必须显式限定。数据隔离部署(PR 预览、租户)不会意外读写public。- 要求事务化迁移:运行时 schema 与
transactional: false(或迁移覆写isTransactional()为false)组合会抛错——没有固定事务时,每条语句可能落在不同的池化连接上,set/reset 无法覆盖 DDL(该检查位于 MigrationRunner.ts)。 - 仅支持顺序扩散:
migrator.up({ schema })会把目标 schema 作为实例状态存于共享的MigrationRunner/MigrationStorage。在同一 ORM 实例上执行Promise.all([orm.migrator.up({ schema: 'a' }), orm.migrator.up({ schema: 'b' })])会交错 set/reset,不受支持。真正需要并行部署时,请使用独立进程(各自MikroORM.init)。 migrations.schema不回退到config.schema:它是 migrator 专属的 opt-in 选项。- MongoDB:Mongo migrator 在传入
{ schema }时会抛出明确错误而非静默忽略。
静态导入迁移(打包场景)
若不想动态导入目录(例如用 webpack 打包代码),可以直接静态导入迁移。可以用显式迁移名,或用隐式的文件名作为迁移名:
import { MikroORM } from '@mikro-orm/core'; import { Migrator } from '@mikro-orm/migrations'; import { Migration20191019195930 } from '../migrations/Migration20191019195930.ts'; import { Migration20191019195931 } from '../migrations/Migration20191019195931.ts'; await MikroORM.init({ extensions: [Migrator], migrations: { migrationsList: [ // 显式迁移名 { name: 'CustomMigrationName', class: Migration20191019195930, }, // 隐式迁移名 Migration20191019195931 ], }, });直接传入的迁移类(未带显式名)会先取迁移实例的name属性解析名称,再回退到类名。新生成的迁移会自动设置name属性——因为压缩器可能混淆类名(同一应用在压缩与非压缩构建下,迁移会以不同名字记录到迁移表)。如果你的迁移文件早于该机制且打包时启用压缩,请手动补上属性:
export class Migration20191019195930 extends Migration { override name = 'Migration20191019195930'; // ... }借助 webpack 的 context module API,可以动态导入整个文件夹的迁移:
import { MikroORM } from '@mikro-orm/core'; import { Migrator } from '@mikro-orm/migrations'; import { basename } from 'path'; const migrations = {}; function importAll(r) { r.keys().forEach( (key) => (migrations[basename(key)] = Object.values(r(key))[0]) ); } importAll(require.context('../migrations', false, /\.ts$/)); const migrationsList = Object.keys(migrations).map((migrationName) => ({ name: migrationName, class: migrations[migrationName], })); await MikroORM.init({ extensions: [Migrator], migrations: { migrationsList, }, });自定义迁移命名
用--nameCLI 选项指定迁移名,会追加到生成前缀之后:
# 生成文件 Migration20230421212713_add_email_property_to_user_table.ts npx mikro-orm migration:create --name=add_email_property_to_user_table通过fileName回调可定制命名约定,甚至强制迁移必须带名字:
migrations: { fileName: (timestamp: string, name?: string) => { // 强制用户提供名字,否则会得到 `Migration20230421212713_undefined` if (!name) { throw new Error('Specify migration name via `mikro-orm migration:create --name=...`'); } return `Migration${timestamp}_${name}`; }, },:::caution 覆写migrations.fileName时务必保证迁移文件可排序——永远不要让文件名以自定义name开头,否则可能导致执行顺序错误。 :::
MongoDB 支持
MongoDB 迁移使用独立包@mikro-orm/migrations-mongodb,其余与现有 CLI 命令兼容。使用this.getCollection()或this.getDb()操作数据库。
:::warning 迁移中应避免使用实体类引用——实体定义会随版本演进,从而破坏旧迁移。请改用this.getCollection()的集合字符串名,或经this.getDb()使用原始Db实例。 :::
可用方法
MongoDB 的Migration类提供以下助手(实现见 packages/migrations-mongodb/src/Migration.ts):
this.getCollection(name)—— 按集合名返回类型化的 MongoDBCollection实例;this.getDb()—— 返回原始 MongoDBDb实例,可完全访问数据库。
事务
Migrator默认开启事务,而 MongoDB 事务有额外要求:集合需预先存在,且必须运行副本集(replicaset)。可以考虑migrations: { transactional: false }禁用。若使用事务,需要通过 MongoDB 的session选项手动为查询提供事务上下文:
await this.getCollection('book').updateMany({}, { $set: { updatedAt: new Date() } }, { session: this.ctx });迁移示例
import { Migration } from '@mikro-orm/migrations-mongodb'; export class MigrationTest1 extends Migration { async up(): Promise<void> { // 用 `this.getCollection()` 直接操作 mongodb 集合 await this.getCollection('book').updateMany({}, { $set: { updatedAt: new Date() } }, { session: this.ctx }); // 或用 `this.getDb()` 完全访问数据库 await this.getDb().collection('book').deleteMany({ foo: true }, { session: this.ctx }); } }已知限制
MySQL
MySQL 中无法回滚 DDL 变更——这类查询会被强制隐式提交,事务因此无法按预期工作(这是 MySQL 隐式提交语义的固有限制,而非 MikroORM 缺陷)。规划 MySQL 迁移时需相应设计不可逆操作。
MongoDB
- 不支持嵌套事务;
- 不做 schema diff;
- 只生成空白迁移。
调试
schema diff 偶尔会产出非预期查询,常见原因出在属性的columnType或default/defaultRaw选项设置上。设置MIKRO_ORM_CLI_VERBOSE环境变量可开启 CLI 的 verbose 日志:它同时输出用于提取当前 schema 的底层查询,以及SchemaComparator中的日志,帮助你理解 ORM 为何认为两列不同、具体是哪些选项有差异。
调试迁移问题更简单的方式是直接使用
schema:update——跳过 Migrator 层,直接测试问题真正所在的 schema 层。
$ MIKRO_ORM_CLI_VERBOSE=1 npx mikro-orm schema:update --dump小结
MikroORM 的迁移系统以「schema diff → 迁移文件 → 事务执行 → 快照比对」为核心闭环:Migration类与MigrationRunner负责执行语义(Migration.ts、MigrationRunner.ts),MigrationStorage维护执行日志表,Migrator串联生成、快照、校验与运行时 schema 上下文(Migrator.ts)。无论你是从零起步、为已有 schema 引入初始迁移、在 CI 中校验 schema 一致性,还是面向 PR 预览与多租户场景做 schema 扩散,都可以基于本文的配置与命令快速落地;遇到 diff 异常时,MIKRO_ORM_CLI_VERBOSE与schema:update --dump是定位问题最直接的入口。
- 后端
【免费下载链接】mikro-orm
TypeScript ORM for Node.js based on Data Mapper, Unit of Work and Identity Map patterns. Supports MongoDB, MySQL, MariaDB, MS SQL Server, PostgreSQL and SQLite/libSQL databases.
相关推荐
MikroORM 迁移指南:从 Schema Diff 到生产环境的多租户部署
MikroORM 迁移指南:从 Schema Diff 到生产环境的多租户部署 MikroORM 将数据库迁移(Migrations)作为一等公民内置,支持基于
后端MikroORM v7 数据库迁移完整指南:从 schema 差异生成、快照机制到生产环境执行
MikroORM v7 数据库迁移完整指南:从 schema 差异生成、快照机制到生产环境执行 MikroORM 将数据库迁移(Migrations)作为一等公
后端MikroORM 数据库迁移完全指南:从 Schema Diff 到生产环境发布
MikroORM 数据库迁移完全指南:从 Schema Diff 到生产环境发布 MikroORM 内置了基于 umzug 的数据库迁移(Migrations)
后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考