Schema 导出
本指南涵盖 schema 导出。你将学会如何:
- 使用
schema:dump将当前数据库 schema 写入 SQL 文件 - 理解 Lucid 在导出文件旁写入的伴随清单文件
- 使用
migration:run --schema-path从导出文件引导新数据库 - 使用
--prune将长迁移历史压缩为单个基线 - 选择何时使用 schema 导出以及何时坚持重放迁移
概述
Schema 导出是一个单独的 SQL 文件,用于重建数据库的当前状态。它包含每个表、索引和视图的结构 DDL,以及 Lucid 迁移记账表(adonis_schema 和 adonis_schema_versions)的内容。
重放长迁移历史需要时间。在全新的 CI 环境中或新贡献者克隆仓库时,当单个 SQL 文件就能重现相同的最终状态时,按顺序运行 300 个迁移纯粹是额外开销。Schema 导出就是那个文件。
导出不替代迁移。你仍然编写迁移来向前演进 schema。导出是一个用于更快引导新数据库的快照,之后 Lucid 恢复运行自快照以来创建的任何待处理迁移。
生成导出
运行 schema:dump 将当前 schema 写入磁盘。Lucid 内省连接并输出两个文件:SQL 导出和一个伴随的 JSON 清单文件。
node ace schema:dump
默认情况下,导出文件落在 database/schema/{connection}-schema.sql,清单文件落在 database/schema/{connection}-schema.meta.json。使用 --path 覆盖位置。
node ace schema:dump --path=./database/snapshots/schema.sql
传递 --connection 来导出非默认连接。
node ace schema:dump --connection=tenant_a
将两个文件都提交到版本控制。它们描述了在导出时刻与你的迁移匹配的 schema,它们应该一起演进。
伴随清单文件
在每个 SQL 导出旁边,Lucid 写入一个 .meta.json 文件。清单记录哪些迁移嵌入在导出中,以便迁移运行器能够区分故意被压缩的迁移和真正缺失的文件。
{
"version": 1,
"connection": "postgres",
"dumpPath": "database/schema/postgres-schema.sql",
"generatedAt": "2026-04-21T10:15:00.000Z",
"schemaTableName": "adonis_schema",
"schemaVersionsTableName": "adonis_schema_versions",
"squashedMigrationNames": [
"database/migrations/1700000000000_create_users_table",
"database/migrations/1700000100000_create_posts_table"
]
}
Lucid 在信任清单之前会根据当前连接验证它。为不同连接或不同 schema 表名生成的清单会被忽略,因此过时的文件永远不会掩盖真正的问题。
从导出文件引导
当两个条件同时满足时,migration:run 会自动加载 schema 导出:
- 目标数据库尚未应用任何迁移(
adonis_schema表为空或不存在)。 - 导出文件存在于默认路径或通过
--schema-path传入的路径。
node ace migration:run
当两个条件都匹配时,Lucid 加载 SQL 导出以代替重放迁移历史,然后运行导出之后创建的任何待处理迁移。例如,如果导出是在存在 300 个迁移时生成的,此后又添加了 5 个新迁移,那么一次全新的 migration:run 会执行一次 SQL 导出,然后运行那 5 个文件。
如果迁移已经被应用过,Lucid 会忽略导出并正常地运行待处理迁移。导出仅引导空数据库。
传递 --schema-path 从自定义位置加载导出。
node ace migration:run --schema-path=./database/snapshots/schema.sql
migration:fresh --schema-path 应用相同的行为:它删除所有表,然后使用导出重建数据库,而非重放每个迁移文件。
node ace migration:fresh --schema-path=./database/snapshots/schema.sql
压缩长迁移历史
一旦项目积累了数百个迁移,早期文件就不再发挥实际作用。它们实际上永远不会再运行,但仍然占用磁盘空间、出现在 diff 中并减慢 CI。--prune 标志将该历史压缩为单个基线。
node ace schema:dump --prune
--prune 运行导出,然后从配置的迁移目录中删除每个文件。迁移文件夹会被重新创建为空,以保持结构不变。此后:
- 新数据库直接从导出文件引导。
- 现有数据库已经在
adonis_schema中记录了每个被修剪的迁移;清单的squashedMigrationNames列表告诉 Lucid 这些名称是故意缺失的,因此回滚和状态检查不会将它们标记为缺失。 - 你编写的新迁移进入空目录并在导出之上运行。
将修剪视为一次性清理操作:
- 在同一提交中提交导出、清单和迁移删除。这三个更改描述单个基线,必须保持同步。
- 在每个人都处于相同迁移状态时执行。如果某个环境仍有待处理迁移,先应用它们。无法回滚到导出之前;
down方法已被删除。 - 避免在发布切割之前立即修剪。在投入生产部署之前,给新基线一些开发时间。
何时使用 schema 导出
在以下情况下使用导出:
- CI 在每次运行时花费大量时间重放迁移。
- 新贡献者在初始设置时等待时间过长,成为阻碍。
- 迁移目录已增长到早期文件不再携带有用信息的程度。
- 你运行许多短期数据库(每分支测试数据库、临时审查环境),引导成本被反复支付。
在以下情况下坚持重放迁移:
- 迁移历史足够短,重放不是瓶颈。
- 你依赖重放历史来验证每个迁移仍然正确应用。
- 你的部署经常回滚到较旧状态,需要最近迁移的
down方法。
修剪和导出不改变生产行为。生产数据库已经在 adonis_schema 中记录了旧迁移;修剪仅从你的仓库中移除文件。
多连接
每个连接获得自己的导出文件和清单。当你的应用使用多个数据库时,为每个连接生成一个。
node ace schema:dump --connection=postgres
node ace schema:dump --connection=analytics
默认路径不会冲突:database/schema/postgres-schema.sql 和 database/schema/analytics-schema.sql。将它们与每个连接的迁移目录一起保存在版本控制中。
以编程方式使用
Ace 命令是 SchemaDumper 类的薄包装。当你需要从应用代码(部署管道、自定义 CLI、设置向导)导出 schema 时,直接使用该类。
import app from '@adonisjs/core/services/app'
import db from '@adonisjs/lucid/services/db'
import { SchemaDumper } from '@adonisjs/lucid/migration'
const dumper = new SchemaDumper(db, app, {
connectionName: 'postgres',
prune: false,
})
await dumper.run()
if (dumper.error) {
console.error(dumper.error)
} else {
console.log(`Schema written to ${dumper.result!.dumpLabel}`)
console.log(`Manifest written to ${dumper.result!.metaLabel}`)
}
await dumper.close()
构造函数接受命令公开的相同三个选项:connectionName、outputPath 和 prune。run() 解析后,检查 dumper.error 和 dumper.result 以查看发生了什么。