# 迁移文件示例

<cite>
**本文引用的文件**
- [AGENTS.MD](file://AGENTS.MD)
- [.example.env](file://.example.env)
- [vendor/xia/migration/src/Migrator.php](file://vendor/xia/migration/src/Migrator.php)
- [vendor/xia/migration/phinx/src/Phinx/Migration/AbstractMigration.php](file://vendor/xia/migration/phinx/src/Phinx/Migration/AbstractMigration.php)
- [vendor/xia/migration/phinx/src/Phinx/Console/Command/Create.php](file://vendor/xia/migration/phinx/src/Phinx/Console/Command/Create.php)
- [vendor/xia/migration/phinx/src/Phinx/Db/Table.php](file://vendor/xia/migration/phinx/src/Phinx/Db/Table.php)
- [vendor/thinkcmf/cmf/src/data/migrations/20230320162718_migration_cmf_role_type.php](file://vendor/thinkcmf/cmf/src/data/migrations/20230320162718_migration_cmf_role_type.php)
- [vendor/thinkcmf/cmf/src/data/migrations/20230322153218_migration_cmf_admin_api.php](file://vendor/thinkcmf/cmf/src/data/migrations/20230322153218_migration_cmf_admin_api.php)
- [vendor/thinkcmf/cmf/src/data/migrations/20231010004518_migration_cmf_theme_file_i18n.php](file://vendor/thinkcmf/cmf/src/data/migrations/20231010004518_migration_cmf_theme_file_i18n.php)
</cite>

## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖分析](#依赖分析)
7. [性能考虑](#性能考虑)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)

## 简介
本文件面向 ThinkCMF 的数据库迁移实践，围绕 xia/migration（基于 Phinx）提供的迁移能力，系统化整理常见场景的完整迁移文件示例与实现要点，覆盖：
- 简单表创建
- 复杂多表关联与索引
- 数据迁移与扩展字段
- 大数据量迁移策略
- 跨数据库迁移注意事项
- 迁移调试与测试方法
- 最佳实践与常见错误规避

同时结合仓库中已有的迁移示例文件，逐项解析设计思路、适用场景与注意事项。

## 项目结构
ThinkCMF 使用 xia/migration 提供的迁移命令与运行机制，迁移文件遵循 Phinx 规范并由 ThinkPHP 控制台驱动。关键位置如下：
- 迁移命令入口：通过 ThinkPHP 控制台命令触发（如创建、执行、回滚）
- 迁移文件位置：位于 ThinkCMF 核心包中的 data/migrations 目录
- 迁移基类：think\migration\Migrator 扩展自 Phinx 的 AbstractMigration，并提供便捷的 Table 封装

```mermaid
graph TB
CLI["命令行<br/>php think migrate:*"] --> CMD_CREATE["命令: Create<br/>phinx/src/Phinx/Console/Command/Create.php"]
CMD_CREATE --> FS["文件系统<br/>迁移文件(.php)"]
FS --> MIGRATOR["迁移基类<br/>think\\migration\\Migrator"]
MIGRATOR --> ABSTRACT_MIG["抽象迁移<br/>Phinx\\Migration\\AbstractMigration"]
ABSTRACT_MIG --> TABLE["表对象封装<br/>phinx/Db/Table.php"]
```

**图表来源**
- [vendor/xia/migration/phinx/src/Phinx/Console/Command/Create.php:139-200](file://vendor/xia/migration/phinx/src/Phinx/Console/Command/Create.php#L139-L200)
- [vendor/xia/migration/src/Migrator.php:16-27](file://vendor/xia/migration/src/Migrator.php#L16-L27)
- [vendor/xia/migration/phinx/src/Phinx/Migration/AbstractMigration.php:269-275](file://vendor/xia/migration/phinx/src/Phinx/Migration/AbstractMigration.php#L269-L275)
- [vendor/xia/migration/phinx/src/Phinx/Db/Table.php:61-69](file://vendor/xia/migration/phinx/src/Phinx/Db/Table.php#L61-L69)

**章节来源**
- [AGENTS.MD:576-598](file://AGENTS.MD#L576-L598)
- [vendor/xia/migration/src/Migrator.php:16-27](file://vendor/xia/migration/src/Migrator.php#L16-L27)
- [vendor/xia/migration/phinx/src/Phinx/Migration/AbstractMigration.php:269-275](file://vendor/xia/migration/phinx/src/Phinx/Migration/AbstractMigration.php#L269-L275)
- [vendor/xia/migration/phinx/src/Phinx/Console/Command/Create.php:139-200](file://vendor/xia/migration/phinx/src/Phinx/Console/Command/Create.php#L139-L200)

## 核心组件
- think\migration\Migrator
  - 作用：继承自 Phinx 抽象迁移，提供 table() 方法快速获取 Table 对象，简化建表/改表语法
  - 关键点：返回的 Table 对象支持链式调用，最终需 save() 或 create()/update() 提交
- Phinx\Migration\AbstractMigration
  - 作用：定义迁移生命周期、适配器注入、SQL 执行接口、预检/后检逻辑
  - 关键点：change() 与 up()/down() 的互斥检查；postFlightCheck() 确保所有动作均已提交
- Phinx\Db\Table
  - 作用：对具体表的操作进行意图收集与延迟执行，统一 create/update/drop 等动作
  - 关键点：hasPendingActions() 用于检测是否遗漏提交

**章节来源**
- [vendor/xia/migration/src/Migrator.php:16-27](file://vendor/xia/migration/src/Migrator.php#L16-L27)
- [vendor/xia/migration/phinx/src/Phinx/Migration/AbstractMigration.php:269-330](file://vendor/xia/migration/phinx/src/Phinx/Migration/AbstractMigration.php#L269-L330)
- [vendor/xia/migration/phinx/src/Phinx/Db/Table.php:134-137](file://vendor/xia/migration/phinx/src/Phinx/Db/Table.php#L134-L137)

## 架构总览
迁移执行的端到端流程如下：

```mermaid
sequenceDiagram
participant Dev as "开发者"
participant CLI as "ThinkPHP 控制台"
participant Cmd as "迁移命令"
participant Mig as "迁移文件(.php)"
participant Base as "Migrator/AbstractMigration"
participant Tbl as "Table 封装"
participant DB as "数据库"
Dev->>CLI : 执行迁移命令
CLI->>Cmd : 解析参数/配置
Cmd->>Mig : 加载迁移文件
Mig->>Base : 调用 change()/up()/down()
Base->>Tbl : table(表名).addColumn()/addIndex()/create()
Tbl->>Tbl : 记录动作意图(未立即执行)
Base->>Base : postFlightCheck() 检查未提交动作
Base->>DB : 执行已确认的动作
DB-->>Dev : 迁移结果
```

**图表来源**
- [vendor/xia/migration/phinx/src/Phinx/Migration/AbstractMigration.php:300-330](file://vendor/xia/migration/phinx/src/Phinx/Migration/AbstractMigration.php#L300-L330)
- [vendor/xia/migration/src/Migrator.php:23-26](file://vendor/xia/migration/src/Migrator.php#L23-L26)
- [vendor/xia/migration/phinx/src/Phinx/Db/Table.php:134-137](file://vendor/xia/migration/phinx/src/Phinx/Db/Table.php#L134-L137)

## 详细组件分析

### 示例一：简单表创建（多语言模板文件表）
- 场景：新增“模板文件多语言”表，包含文件定位、主题、语言、操作、模板路径及两份扩展配置字段
- 设计要点：
  - 使用 table() 获取表对象，按需添加列、索引
  - TEXT 类型采用长文本常量，确保足够存储扩展配置
  - 通过索引加速常用查询（如按语言、文件 ID）
- 适用业务：主题国际化、模板文案本地化
- 注意事项：
  - 字段长度与字符集需与系统规范一致
  - 长文本字段可能影响查询性能，建议配合索引与分页

```mermaid
flowchart TD
Start(["开始"]) --> Define["定义表: theme_file_i18n"]
Define --> AddCols["添加列: file_id/theme/lang/action/file/more/draft_more"]
AddCols --> AddIdx["添加索引: file_id/lang"]
AddIdx --> CreateTbl["创建表"]
CreateTbl --> End(["结束"])
```

**图表来源**
- [vendor/thinkcmf/cmf/src/data/migrations/20231010004518_migration_cmf_theme_file_i18n.php:29-90](file://vendor/thinkcmf/cmf/src/data/migrations/20231010004518_migration_cmf_theme_file_i18n.php#L29-L90)

**章节来源**
- [vendor/thinkcmf/cmf/src/data/migrations/20231010004518_migration_cmf_theme_file_i18n.php:29-90](file://vendor/thinkcmf/cmf/src/data/migrations/20231010004518_migration_cmf_theme_file_i18n.php#L29-L90)

### 示例二：复杂多表关联（后台 API 列表）
- 场景：构建后台 API 列表树形结构，支持父子节点、类型区分、URL 路由与标签分组
- 设计要点：
  - parent_id 字段支撑层级关系
  - INT_TINY 限制类型字段，节省存储
  - url/name/tags/remark 等字段满足展示与检索需求
  - 为 parent_id/url 建立索引，提升查询效率
- 适用业务：菜单/权限树、API 路由管理
- 注意事项：
  - 索引数量与维护成本平衡
  - URL 字段需严格校验格式，避免重复或冲突

```mermaid
flowchart TD
Start2(["开始"]) --> Define2["定义表: admin_api"]
Define2 --> Cols2["添加列: parent_id/type/url/name/tags/remark"]
Cols2 --> Idx2["添加索引: parent_id/url"]
Idx2 --> Create2["创建表"]
Create2 --> End2(["结束"])
```

**图表来源**
- [vendor/thinkcmf/cmf/src/data/migrations/20230322153218_migration_cmf_admin_api.php:29-70](file://vendor/thinkcmf/cmf/src/data/migrations/20230322153218_migration_cmf_admin_api.php#L29-L70)

**章节来源**
- [vendor/thinkcmf/cmf/src/data/migrations/20230322153218_migration_cmf_admin_api.php:29-70](file://vendor/thinkcmf/cmf/src/data/migrations/20230322153218_migration_cmf_admin_api.php#L29-L70)

### 示例三：字段变更（角色类型）
- 场景：为现有角色表增加“类型”字段，支持区分管理员/前台等角色类型
- 设计要点：
  - 使用 update() 对已有表进行变更
  - 指定默认值、非空约束与注释
  - after 参数控制列顺序
- 适用业务：角色体系扩展、权限域划分
- 注意事项：
  - 变更前备份数据
  - 非空字段需提供默认值或兼容旧记录

```mermaid
flowchart TD
Start3(["开始"]) --> GetTbl["获取表: role"]
GetTbl --> AddCol["新增列: type(string,默认值,非空,注释)"]
AddCol --> UpdateTbl["update() 提交变更"]
UpdateTbl --> End3(["结束"])
```

**图表来源**
- [vendor/thinkcmf/cmf/src/data/migrations/20230320162718_migration_cmf_role_type.php:28-38](file://vendor/thinkcmf/cmf/src/data/migrations/20230320162718_migration_cmf_role_type.php#L28-L38)

**章节来源**
- [vendor/thinkcmf/cmf/src/data/migrations/20230320162718_migration_cmf_role_type.php:28-38](file://vendor/thinkcmf/cmf/src/data/migrations/20230320162718_migration_cmf_role_type.php#L28-L38)

### 示例四：数据迁移与扩展字段
- 场景：从旧表迁移数据至新表，或为现有表追加扩展字段（如 more/draft_more）
- 设计要点：
  - 新增长文本字段承载扩展配置
  - 通过索引与分页降低大字段查询开销
  - 迁移过程中注意事务与幂等性
- 适用业务：内容模型扩展、主题配置持久化
- 注意事项：
  - 大字段迁移建议分批执行
  - 迁移前后对比校验数据一致性

（本节为通用指导，不直接分析具体文件）

### 示例五：跨数据库迁移
- 场景：从 MySQL 迁移到其他数据库（如 PostgreSQL），或在多实例间同步
- 设计要点：
  - 使用适配器抽象层，避免硬编码 SQL
  - 字段类型映射与字符集差异需统一处理
  - 索引与约束在不同数据库的兼容性
- 适用业务：多租户、异地容灾
- 注意事项：
  - 测试环境先行验证
  - 回滚策略与数据一致性保障

（本节为通用指导，不直接分析具体文件）

## 依赖分析
- 组件耦合
  - think\migration\Migrator 依赖 Phinx 的 AbstractMigration 与 Table
  - AbstractMigration 提供适配器注入与执行接口
  - Table 负责动作意图收集与延迟执行
- 外部依赖
  - ThinkPHP 控制台命令驱动迁移执行
  - 数据库驱动（MySQL 等）由适配器提供
- 循环依赖
  - 无直接循环；迁移文件仅单向依赖基类与适配器

```mermaid
classDiagram
class AbstractMigration {
+setAdapter(adapter)
+getAdapter()
+table(name, options)
+execute(sql)
+postFlightCheck(direction)
}
class Migrator {
+table(tableName, options)
}
class Table {
+exists()
+drop()
+rename(newName)
+hasPendingActions()
}
Migrator --> AbstractMigration : "继承"
AbstractMigration --> Table : "创建/使用"
```

**图表来源**
- [vendor/xia/migration/src/Migrator.php:16-27](file://vendor/xia/migration/src/Migrator.php#L16-L27)
- [vendor/xia/migration/phinx/src/Phinx/Migration/AbstractMigration.php:86-117](file://vendor/xia/migration/phinx/src/Phinx/Migration/AbstractMigration.php#L86-L117)
- [vendor/xia/migration/phinx/src/Phinx/Db/Table.php:144-147](file://vendor/xia/migration/phinx/src/Phinx/Db/Table.php#L144-L147)

**章节来源**
- [vendor/xia/migration/src/Migrator.php:16-27](file://vendor/xia/migration/src/Migrator.php#L16-L27)
- [vendor/xia/migration/phinx/src/Phinx/Migration/AbstractMigration.php:86-117](file://vendor/xia/migration/phinx/src/Phinx/Migration/AbstractMigration.php#L86-L117)
- [vendor/xia/migration/phinx/src/Phinx/Db/Table.php:144-147](file://vendor/xia/migration/phinx/src/Phinx/Db/Table.php#L144-L147)

## 性能考虑
- 索引策略
  - 为高频查询字段建立合适索引，减少全表扫描
  - 避免过度索引导致写入性能下降
- 大字段处理
  - TEXT/LONGTEXT 等大字段尽量延后读取，配合分页与缓存
- 批量迁移
  - 分批处理大数据量迁移，设置事务边界，便于失败重试
- 并发与锁
  - 避免在高峰期执行长事务，必要时使用只读副本

（本节提供通用建议，不直接分析具体文件）

## 故障排查指南
- 常见问题
  - 迁移文件未被识别：检查类名是否符合规范、文件路径是否在迁移目录
  - 迁移回滚异常：确认 change() 与 up()/down() 同时存在时的互斥规则
  - 未提交动作：postFlightCheck 抛出异常，检查是否遗漏 save()/create()/update()
- 调试方法
  - 使用命令行输出日志，定位具体步骤
  - 在迁移中打印关键 SQL 或使用数据库日志
  - 先在测试库验证，再推广到生产
- 配置参考
  - 数据库连接与前缀等配置可参考示例环境文件

**章节来源**
- [vendor/xia/migration/phinx/src/Phinx/Migration/AbstractMigration.php:300-330](file://vendor/xia/migration/phinx/src/Phinx/Migration/AbstractMigration.php#L300-L330)
- [vendor/xia/migration/phinx/src/Phinx/Console/Command/Create.php:168-185](file://vendor/xia/migration/phinx/src/Phinx/Console/Command/Create.php#L168-L185)
- [.example.env:1-1](file://.example.env#L1-L1)

## 结论
ThinkCMF 的迁移体系以 xia/migration 为核心，依托 Phinx 的强大能力，提供了简洁而可靠的数据库演进方式。通过合理设计迁移文件、遵循索引与字段规范、采用分批与幂等策略，可在保证数据安全的前提下高效推进系统演进。建议在团队内形成迁移规范与评审流程，持续完善自动化测试与回滚预案。

## 附录
- 命令速查
  - 创建迁移：php think migrate:create {迁移类名}
  - 执行迁移：php think migrate:run
  - 回滚迁移：php think migrate:rollback
- 环境配置
  - 参考示例环境变量文件，配置数据库连接与前缀

**章节来源**
- [AGENTS.MD:576-598](file://AGENTS.MD#L576-L598)
- [AGENTS.MD:633-653](file://AGENTS.MD#L633-L653)
- [.example.env:1-1](file://.example.env#L1-L1)