news 2026/9/28 6:21:05

MikroORM 数据库迁移完全指南:从 Schema 快照到多租户运行时 Schema 上下文

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MikroORM 数据库迁移完全指南:从 Schema 快照到多租户运行时 Schema 上下文
  • 后端

【免费下载链接】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.

项目地址:https://gitcode.com/gh_mirrors/mi/mikro-orm
点击查看免费下载

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_NAME
  • MIKRO_ORM_MIGRATIONS_PATH
  • MIKRO_ORM_MIGRATIONS_PATH_TS
  • MIKRO_ORM_MIGRATIONS_GLOB
  • MIKRO_ORM_MIGRATIONS_TRANSACTIONAL
  • MIKRO_ORM_MIGRATIONS_DISABLE_FOREIGN_KEYS
  • MIKRO_ORM_MIGRATIONS_ALL_OR_NOTHING
  • MIKRO_ORM_MIGRATIONS_DROP_TABLES
  • MIKRO_ORM_MIGRATIONS_SAFE
  • MIKRO_ORM_MIGRATIONS_SILENT
  • MIKRO_ORM_MIGRATIONS_EMIT
  • MIKRO_ORM_MIGRATIONS_SNAPSHOT
  • MIKRO_ORM_MIGRATIONS_SNAPSHOT_ON_MIGRATE
  • MIKRO_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 migrate

create()返回{ 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)。

驱动SetReset
PostgreSQLSET search_path TO "x"RESET search_path
MySQL / MariaDBUSE `x`USE `<config.dbName>`
OracleALTER 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.

项目地址:https://gitcode.com/gh_mirrors/mi/mikro-orm
点击查看免费下载
上一篇:OpCore Simplify:让黑苹果配置从技术挑战变成轻松体验
下一篇:RevokeMsgPatcher:彻底告别消息撤回困扰的终极Windows工具指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/28 6:18:55

20种机器学习算法Python代码包:从跑通到避坑的完整指南

简介&#xff1a;这份资源面向机器学习入门与进阶学习者&#xff0c;系统整理了20种常见算法的Python实现&#xff0c;覆盖线性回归、逻辑回归、BP神经网络、SVM支持向量机、K-Means聚类、PCA主成分分析以及异常检测等经典模型&#xff0c;适合希望从理论走向动手实践、需要可运…

作者头像 李华
网站建设 2026/9/28 6:18:27

CCC认证全流程拆解:申请、工厂检查、费用周期与合规价值

聊到产品认证&#xff0c;很多做硬件和消费电子的朋友可能都听说过“CCC”三个字母。我这些年经手过不少CCC项目的申请、审厂和整改&#xff0c;也亲眼见过产品因为证书问题被渠道平台直接下架的情况。说句实在话&#xff0c;CCC认证在国内市场就像产品的“入场券”&#xff0c…

作者头像 李华
网站建设 2026/9/28 6:18:26

分布式实时计算核心解析:从流处理原理到Flink实战避坑

1. 分布式计算的“实时”究竟是什么&#xff1a;先搞清楚批处理和流处理的本质差异这几年做大数据方向的技术分享&#xff0c;被问得最多的一个问题不是“Flink和Spark哪个好”&#xff0c;而是“你们说的实时到底是指多快”。有人在简历里写“熟练掌握实时计算”&#xff0c;但…

作者头像 李华
网站建设 2026/9/28 6:18:00

电力系统多产消者非合作博弈能量共享的分布式优化与MATLAB实现

看到【电力系统】基于分布式优化的多产消者非合作博弈能量共享附matlab代码这个标题&#xff0c;很多人的第一反应是&#xff1a;四个术语叠在一起&#xff0c;怕不是又一个把概念拼起来就跑的仿真水论文。我最早拿到这个问题的时候也是这么想的&#xff0c;直到真正动手把模型…

作者头像 李华
网站建设 2026/9/28 6:17:33

Flink窗口实战:滑动、会话、全局窗口机制详解

说实话&#xff0c;很多人对Flink窗口的理解停留在timeWindow(Time.seconds(10))这种最基础的滚动窗口上。一旦遇到"统计最近5分钟的交易量&#xff0c;每30秒刷新一次"这种需求&#xff0c;就开始纠结&#xff1b;再遇上"用户连续操作超过2分钟没动作&#xff…

作者头像 李华