Schema 导出

Schema 导出

本指南涵盖 schema 导出。你将学会如何:

  • 使用 schema:dump 将当前数据库 schema 写入 SQL 文件
  • 理解 Lucid 在导出文件旁写入的伴随清单文件
  • 使用 migration:run --schema-path 从导出文件引导新数据库
  • 使用 --prune 将长迁移历史压缩为单个基线
  • 选择何时使用 schema 导出以及何时坚持重放迁移

概述

Schema 导出是一个单独的 SQL 文件,用于重建数据库的当前状态。它包含每个表、索引和视图的结构 DDL,以及 Lucid 迁移记账表(adonis_schemaadonis_schema_versions)的内容。

重放长迁移历史需要时间。在全新的 CI 环境中或新贡献者克隆仓库时,当单个 SQL 文件就能重现相同的最终状态时,按顺序运行 300 个迁移纯粹是额外开销。Schema 导出就是那个文件。

导出不替代迁移。你仍然编写迁移来向前演进 schema。导出是一个用于更快引导新数据库的快照,之后 Lucid 恢复运行自快照以来创建的任何待处理迁移。

生成导出

运行 schema:dump 将当前 schema 写入磁盘。Lucid 内省连接并输出两个文件:SQL 导出和一个伴随的 JSON 清单文件。

terminal
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 文件。清单记录哪些迁移嵌入在导出中,以便迁移运行器能够区分故意被压缩的迁移和真正缺失的文件。

database/schema/postgres-schema.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 传入的路径。
terminal
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.sqldatabase/schema/analytics-schema.sql。将它们与每个连接的迁移目录一起保存在版本控制中。

以编程方式使用

Ace 命令是 SchemaDumper 类的薄包装。当你需要从应用代码(部署管道、自定义 CLI、设置向导)导出 schema 时,直接使用该类。

scripts/dump_schema.ts
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()

构造函数接受命令公开的相同三个选项:connectionNameoutputPathprunerun() 解析后,检查 dumper.errordumper.result 以查看发生了什么。