# 迁移文件结构

<cite>
**本文引用的文件**
- [AGENTS.MD](file://AGENTS.MD)
- [AbstractMigration.php](file://vendor/xia/migration/phinx/src/Phinx/Migration/AbstractMigration.php)
- [MigrationInterface.php](file://vendor/xia/migration/phinx/src/Phinx/Migration/MigrationInterface.php)
- [Manager.php](file://vendor/xia/migration/phinx/src/Phinx/Migration/Manager.php)
- [Environment.php](file://vendor/xia/migration/phinx/src/Phinx/Migration/Manager/Environment.php)
- [IrreversibleMigrationException.php](file://vendor/xia/migration/phinx/src/Phinx/Migration/IrreversibleMigrationException.php)
- [composer.lock](file://composer.lock)
- [.example.env](file://.example.env)
</cite>

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

## 简介
本文件面向 ThinkCMF 项目，系统性梳理数据库迁移文件的结构与编写规范，覆盖迁移类的继承关系、必需方法、up()/down() 的实现要求与最佳实践、数据库操作方法（字段定义、索引创建、约束设置）、版本控制与命名约定，并提供完整示例与常见场景实现方案。ThinkCMF 使用 xia/migration 包集成 Phinx 迁移能力，迁移文件遵循 Phinx 命名与执行规范。

## 项目结构
- ThinkCMF 通过 composer 引入 xia/migration（基于 Phinx），迁移命令由 ThinkPHP 控制台驱动。
- 迁移文件由 xia/migration 包管理，遵循 Phinx 的命名与加载机制。
- 迁移文件通常放置在应用或框架约定的迁移目录中（具体路径由配置决定），文件名采用“时间戳_类名.php”的形式，例如：20230320162718_create_users_table.php。

```mermaid
graph TB
A["ThinkCMF 应用<br/>ThinkPHP 控制台"] --> B["迁移命令入口<br/>php think migrate:*"]
B --> C["迁移管理器 Manager<br/>扫描/加载迁移文件"]
C --> D["环境 Environment<br/>连接数据库/适配器"]
D --> E["迁移执行<br/>执行 up()/down() 或 change()"]
E --> F["日志记录 phinxlog<br/>版本状态维护"]
```

图表来源
- [Manager.php:695-791](file://vendor/xia/migration/phinx/src/Phinx/Migration/Manager.php#L695-L791)
- [Environment.php:74-124](file://vendor/xia/migration/phinx/src/Phinx/Migration/Manager/Environment.php#L74-L124)

章节来源
- [AGENTS.MD:576-599](file://AGENTS.MD#L576-L599)
- [composer.lock:1121-1167](file://composer.lock#L1121-L1167)

## 核心组件
- 迁移接口与抽象类
  - MigrationInterface 定义迁移对象必须实现的方法集合（适配器注入、输入输出、版本号、方向标记、SQL 执行、表操作、预检/后检等）。
  - AbstractMigration 实现 MigrationInterface，提供 table()、execute()/query()、hasTable()、createDatabase()/dropDatabase() 等常用方法，并负责迁移前后检查与事务包裹。
- 迁移管理器与环境
  - Manager 负责扫描迁移文件、解析版本、按顺序执行 up/down、打印状态、回滚到目标版本等。
  - Environment 负责建立数据库适配器、封装事务、调用迁移并记录执行日志。
- 不可逆异常
  - IrreversibleMigrationException 用于当使用 change() 且无法反向执行时抛出的异常类型。

章节来源
- [MigrationInterface.php:19-244](file://vendor/xia/migration/phinx/src/Phinx/Migration/MigrationInterface.php#L19-L244)
- [AbstractMigration.php:27-331](file://vendor/xia/migration/phinx/src/Phinx/Migration/AbstractMigration.php#L27-L331)
- [Manager.php:25-82](file://vendor/xia/migration/phinx/src/Phinx/Migration/Manager.php#L25-L82)
- [Environment.php:19-64](file://vendor/xia/migration/phinx/src/Phinx/Migration/Manager/Environment.php#L19-L64)
- [IrreversibleMigrationException.php:18-20](file://vendor/xia/migration/phinx/src/Phinx/Migration/IrreversibleMigrationException.php#L18-L20)

## 架构总览
迁移执行的关键流程如下：

```mermaid
sequenceDiagram
participant CLI as "命令行"
participant Manager as "迁移管理器"
participant Env as "环境"
participant Adapter as "数据库适配器"
participant Mig as "迁移类"
CLI->>Manager : 执行 migrate : run / migrate : rollback
Manager->>Manager : 扫描并加载迁移文件
Manager->>Env : 获取环境配置/版本日志
Env->>Adapter : 初始化适配器/事务包装
Manager->>Env : executeMigration(Mig, 方向)
Env->>Mig : setAdapter/预检/初始化(init)
alt 使用 change()
Mig->>Adapter : 正向/反向记录命令
else 使用 up()/down()
Mig->>Adapter : 执行对应方法
end
Adapter-->>Env : 提交事务/记录日志
Env-->>Manager : 返回执行结果
Manager-->>CLI : 输出状态/耗时
```

图表来源
- [Manager.php:311-395](file://vendor/xia/migration/phinx/src/Phinx/Migration/Manager.php#L311-L395)
- [Environment.php:74-124](file://vendor/xia/migration/phinx/src/Phinx/Migration/Manager/Environment.php#L74-L124)

## 详细组件分析

### 迁移类继承关系与必需方法
- 继承关系
  - 迁移类需继承 AbstractMigration（或其子类），从而获得统一的数据库操作能力与生命周期钩子。
- 必需方法
  - up(): 定义“向上”迁移逻辑（如创建/修改表）。
  - down(): 定义“向下”回滚逻辑（与 up() 对称）。
  - 可选 change(): 使用“变更记录器”实现可逆变更；若同时存在 change() 与 up()/down()，则忽略后者。
  - init(): 迁移执行前的初始化逻辑（可选）。
  - 预检/后检：AbstractMigration 在执行前后进行检查，确保所有变更已提交，避免遗漏操作。

章节来源
- [MigrationInterface.php:24-130](file://vendor/xia/migration/phinx/src/Phinx/Migration/MigrationInterface.php#L24-L130)
- [AbstractMigration.php:27-331](file://vendor/xia/migration/phinx/src/Phinx/Migration/AbstractMigration.php#L27-L331)

### up() 与 down() 的实现要求与最佳实践
- up() 最佳实践
  - 使用 table() 获取表对象，链式定义列、索引、约束后再 save()。
  - 保持幂等：多次执行 up() 不应产生重复结构。
  - 分步提交：复杂变更建议拆分为多个迁移文件，便于回滚与追踪。
  - 事务安全：Manager/Environment 已包裹事务，但避免在单个迁移中做大量长事务操作。
- down() 最佳实践
  - 与 up() 对称：删除列/索引/约束的顺序要与 up() 相反。
  - 可逆性：尽量避免不可逆操作；若不可避免，使用 change() 并在 down() 中通过代理适配器反向执行。
  - 清理数据：如涉及数据清理，需明确备份策略或在 change() 中记录反向动作。
- change() 的使用
  - 适合简单对称变更；Manager 会自动记录正向命令并在 down() 时反向执行。
  - 若变更不可逆，抛出 IrreversibleMigrationException。

```mermaid
flowchart TD
Start(["开始迁移"]) --> CheckChange["是否存在 change() 方法?"]
CheckChange --> |是| UseChange["执行 change()<br/>记录正向命令"]
UseChange --> DownDirection{"方向为 down?"}
DownDirection --> |是| Replay["代理适配器反向重放命令"]
DownDirection --> |否| Commit["提交并记录日志"]
CheckChange --> |否| UseUpDown["执行 up() 或 down()"]
UseUpDown --> Commit
Commit --> End(["结束"])
```

图表来源
- [Environment.php:95-112](file://vendor/xia/migration/phinx/src/Phinx/Migration/Manager/Environment.php#L95-L112)
- [IrreversibleMigrationException.php:18-20](file://vendor/xia/migration/phinx/src/Phinx/Migration/IrreversibleMigrationException.php#L18-L20)

章节来源
- [Manager.php:311-395](file://vendor/xia/migration/phinx/src/Phinx/Migration/Manager.php#L311-L395)
- [Environment.php:74-124](file://vendor/xia/migration/phinx/src/Phinx/Migration/Manager/Environment.php#L74-L124)

### 数据库操作方法与常见场景
- 表操作
  - table(name, options): 获取表对象，后续可链式定义列、索引、约束。
  - hasTable(name): 判断表是否存在。
  - dropDatabase(name)/createDatabase(name, options): 数据库级操作（谨慎使用）。
- 列与索引
  - 在表对象上定义列类型、长度、默认值、注释、是否为空等。
  - 定义主键、唯一键、普通索引、复合索引。
  - 设置外键约束（如适用）。
- 查询与执行
  - execute(sql)/query(sql): 直接执行 SQL。
  - getQueryBuilder(): 使用查询构建器执行复杂查询。
  - fetchRow()/fetchAll(): 查询结果获取。
- 事务与日志
  - 管理器/环境自动开启事务并提交；执行完成后记录 phinxlog 日志。

章节来源
- [AbstractMigration.php:192-275](file://vendor/xia/migration/phinx/src/Phinx/Migration/AbstractMigration.php#L192-L275)
- [Environment.php:88-124](file://vendor/xia/migration/phinx/src/Phinx/Migration/Manager/Environment.php#L88-L124)

### 版本控制与命名约定
- 命名规范
  - 文件名采用“时间戳_类名.php”，如 20230320162718_CreateUsersTable.php。
  - 类名与文件名一致，首字母大写驼峰。
- 版本顺序
  - Manager 支持按创建时间或执行时间排序，确保迁移按预期顺序执行。
- 版本记录
  - 执行后在 phinxlog 表中记录版本、开始/结束时间、方向等信息，便于回滚与状态查询。

章节来源
- [Manager.php:695-791](file://vendor/xia/migration/phinx/src/Phinx/Migration/Manager.php#L695-L791)
- [Environment.php:247-266](file://vendor/xia/migration/phinx/src/Phinx/Migration/Manager/Environment.php#L247-L266)

### 迁移命令与环境配置
- 常用命令
  - 创建迁移：php think migrate:create CreateUsersTable
  - 执行迁移：php think migrate:run
  - 回滚迁移：php think migrate:rollback
- 环境配置
  - 数据库连接、字符集、表前缀等通过环境选项传递给适配器。
  - .example.env 提供数据库配置示例（如 DATABASE_PREFIX、DATABASE_CHARSET 等）。

章节来源
- [AGENTS.MD:580-593](file://AGENTS.MD#L580-L593)
- [.example.env:1-1](file://.example.env#L1-L1)

## 依赖分析
- ThinkCMF 依赖 xia/migration（基于 Phinx），通过 composer 管理。
- 迁移命令注册由 think\migration\Service 提供，遵循 ThinkPHP 服务发现机制。
- 运行时通过 Manager/Environment/Adapter 协作完成迁移加载、执行与日志记录。

```mermaid
graph TB
CMF["ThinkCMF 应用"] --> XIA["xia/migration 包"]
XIA --> PHINX["Phinx 核心<br/>AbstractMigration/Manager/Environment"]
CMF --> CMD["ThinkPHP 控制台命令"]
CMD --> XIA
```

图表来源
- [composer.lock:1121-1167](file://composer.lock#L1121-L1167)
- [Manager.php:76-81](file://vendor/xia/migration/phinx/src/Phinx/Migration/Manager.php#L76-L81)

章节来源
- [composer.lock:1121-1167](file://composer.lock#L1121-L1167)

## 性能考虑
- 迁移执行期间建议避免长时间运行的 DDL/DML，分批处理大型表结构变更。
- 合理使用索引：先建索引再导入数据，避免全表扫描。
- 事务粒度：单次迁移尽量保持在合理时间内，减少锁竞争。
- 批量操作：使用批量插入/更新减少往返次数。

## 故障排查指南
- 迁移后仍有“待提交动作”
  - AbstractMigration.postFlightCheck 会在执行后检查是否有未提交的表操作，若抛出异常需补全 save() 或相应变更。
- change() 不可逆
  - 若使用 change() 且 down() 无法反向，抛出 IrreversibleMigrationException，需改用 up()/down() 或补充反向逻辑。
- 版本冲突或重复
  - Manager 会检测重复版本或同名迁移类，需修正文件名或类名。
- 环境未找到或适配器错误
  - Environment 会校验适配器与连接参数，确保 DATABASE_* 配置正确。

章节来源
- [AbstractMigration.php:323-331](file://vendor/xia/migration/phinx/src/Phinx/Migration/AbstractMigration.php#L323-L331)
- [IrreversibleMigrationException.php:18-20](file://vendor/xia/migration/phinx/src/Phinx/Migration/IrreversibleMigrationException.php#L18-L20)
- [Manager.php:717-784](file://vendor/xia/migration/phinx/src/Phinx/Migration/Manager.php#L717-L784)
- [Environment.php:328-340](file://vendor/xia/migration/phinx/src/Phinx/Migration/Manager/Environment.php#L328-L340)

## 结论
ThinkCMF 的迁移体系基于 xia/migration（Phinx）实现，具备清晰的类继承关系、统一的接口契约与完善的执行生命周期。遵循命名规范、合理拆分迁移、善用 change()/up()/down() 与表对象 API，可高效、安全地演进数据库结构。配合 Manager/Environment 的版本控制与日志记录，能够稳定支撑生产环境的数据库变更。

## 附录
- 命令速查
  - 创建迁移：php think migrate:create CreateUsersTable
  - 执行迁移：php think migrate:run
  - 回滚迁移：php think migrate:rollback
- 常见场景
  - 创建表：在 up() 中使用 table()->create()，在 down() 中 drop()。
  - 修改表：在 up() 中使用 table()->addColumn()/modifyColumn()/addIndex() 等，down() 中逆向操作。
  - 删除表：up() 中 drop()，down() 中重建（如需要）。
  - 外键约束：在 up() 中添加外键，down() 中先删约束再删列或表。
- 环境变量参考
  - DATABASE_PREFIX、DATABASE_CHARSET、DATABASE_HOSTNAME、DATABASE_DATABASE 等。

章节来源
- [AGENTS.MD:580-593](file://AGENTS.MD#L580-L593)
- [.example.env:1-1](file://.example.env#L1-L1)