Documentation
¶
Index ¶
Constants ¶
This section is empty.
Variables ¶
var Registry []Migration
Registry 聚合所有已注册迁移,注册顺序 = 执行顺序。 具体迁移包(如 internal/migrate/v160)在 init() 里调用 Register 自注册; migrate.Run 遍历本注册表执行,对具体迁移无感知。
Functions ¶
func MarkStepsDone ¶
MarkStepsDone 原子登记无需执行的数据迁移。它与 markStep 的“状态写入失败仅告警” 语义不同:新库/最终 schema 必须一次性得到全部 done 或完全不写入,避免进程中断 后留下半组状态并在下次被误当作待恢复的旧库迁移。
Types ¶
type MigrateState ¶
type MigrateState struct {
ID int64 `gorm:"column:id;primaryKey;autoIncrement" json:"id"`
Migration string `gorm:"column:migration;not null;uniqueIndex:uk_migration_step" json:"migration"` // 迁移标识,如 "v1.6.0-chapter-id-refactor"
Step string `gorm:"column:step;not null;uniqueIndex:uk_migration_step" json:"step"` // 迁移内 step 标识(语义化 key,如 "1-crossref-data")
Status string `gorm:"column:status;not null;index" json:"status"` // "running" | "done" | "failed"(未开始无行)
StartedAt *time.Time `gorm:"column:started_at" json:"started_at"` // 本 step 开始时间,nullable
FinishedAt *time.Time `gorm:"column:finished_at" json:"finished_at"` // 本 step 完成时间,nullable
Error string `gorm:"column:error" json:"error"` // failed 时的错误信息
CreatedAt time.Time `gorm:"column:created_at;autoCreateTime" json:"created_at"`
UpdatedAt time.Time `gorm:"column:updated_at;autoUpdateTime" json:"updated_at"`
}
MigrateState 是迁移进度跟踪表,按"迁移 + step"两级记录。
设计原则:
- 一行 = (migration, step)。migration 标识一次大迁移(如 "v1.6.0-chapter-id-refactor"), step 标识该迁移内的执行步骤(语义化 key,如 "1-crossref-data")
- status 取值:running | done | failed(未开始 = 无行,stepStatus 返回空串)
- 幂等:迁移启动时查 migration 组内非 done 的 step,逐个执行;每步"内部执行完再写 done"
- 中断续跑:某 step 写 done 前中断 → 该 step 未 done → 下次从它重跑(step 内部幂等)
- 备份/完成判断:查 migration 组的行是否全部 done,只看本组,不看其他迁移
- 新用户 DB 初始化后所有 step INSERT 为 done(无需迁移)
时间戳语义:
- started_at:本 step 开始执行时间(nullable,未执行时为 NULL)
- finished_at:本 step 执行完成时间(nullable,running 时为 NULL)
- error:failed 时填写错误信息,便于诊断中断原因
type Migration ¶
type Migration struct {
Name string // 迁移标识,如 "v1.6.0-chapter-id-refactor",写入 migrate_state.migration
Description string // 迁移目的简述(本次迁移为了什么、主要做什么),打印进日志便于排查
Destructive bool // 是否破坏性迁移(删列/rename/数据重写等):true 时 migrate.Run 会在执行前自动备份全量数据
// NeedsMigration 仅在既有数据库缺少本 migration 的 migrate_state 时调用,识别
// 是否仍处于该 migration 的旧 schema。应返回 error 拒绝无法安全识别的混合 schema。
NeedsMigration func(db *gorm.DB) (bool, error)
PreSchemaSteps []Step // 当前 model AutoMigrate 前执行,例如历史字段改名
PostSchemaSteps []Step // 当前 model AutoMigrate 后执行,例如数据重写、文件迁移、删旧列
}
Migration 描述一次迁移。PreSchemaSteps 必须在当前 model 的 AutoMigrate 前运行; PostSchemaSteps 则在其后运行。两类步骤均按 Registry 注册顺序执行。
type Plan ¶
type Plan struct {
Migration Migration
Action PlanAction
}
Plan 是根据启动前 schema 和 migrate_state 得出的单次迁移计划。
type PlanAction ¶
type PlanAction uint8
PlanAction 是一次启动中对一个 migration 的执行计划。
const ( PlanSkip PlanAction = iota // 所有已知步骤均 done PlanRun // 运行步骤,或从未完成状态恢复 PlanMarkDone // 当前 schema 无需迁移,仅登记步骤完成 )
type Step ¶
type Step interface {
Key() string // 步骤标识(迁移内序数 N-描述,如 "1-crossref-data")
Run(db *gorm.DB, log *slog.Logger) error // 业务逻辑,幂等可重入
}
Step 描述一个迁移步骤:由 RunSteps 统一驱动。
契约:Run 内部必须幂等可重入——自身完成条件(HasColumn / IS NULL / 目标文件存在等) 已满足时直接返回 nil。中断后框架从"未 done"的 step 重跑,靠此契约保证安全。
设计:Step 是接口而非结构体。具体迁移包(如 internal/migrate/v160)用自己的私有 step 类型实现它并注册进 Registry,migrate 包无需感知具体迁移。