// Command migrate 是独立的数据库结构迁移入口:手动执行,服务启动不会触发迁移。 // // 用法: // // go run ./cmd/migrate up # 执行到最新版本 // go run ./cmd/migrate down # 全量回滚 // go run ./cmd/migrate steps 2 # 向上 2 步(负数向下) // go run ./cmd/migrate version # 查看当前版本与脏库状态 // go run ./cmd/migrate force 3 # 修复脏库:强制设置版本号 package main import ( "fmt" "os" "strconv" "git.lzcwy.cn/zhengchiliu/zt-closet-backend/pkg/migration" "git.lzcwy.cn/zhengchiliu/zt-closet-backend/pkg/setting" ) const usage = `用法: go run ./cmd/migrate up 执行到最新版本 go run ./cmd/migrate down 全量回滚所有迁移 go run ./cmd/migrate steps N 向上 N 步(N 为负数时向下) go run ./cmd/migrate version 查看当前版本与脏库状态 go run ./cmd/migrate force V 强制设置版本号并清除脏标记` func main() { if err := run(os.Args[1:]); err != nil { fmt.Fprintf(os.Stderr, "migrate failed: %v\n", err) os.Exit(1) } } func run(args []string) error { if len(args) == 0 { fmt.Println(usage) return nil } // 仅读取 Mysql 配置段,不复用 main.go 的 setupSetting(后者会强制校验 JWT 等无关配置)。 mysqlSetting, err := loadMysqlSetting() if err != nil { return err } switch args[0] { case "up": if err := migration.Up(mysqlSetting); err != nil { return err } fmt.Println("migrate up: done") return nil case "down": if err := migration.Down(mysqlSetting); err != nil { return err } fmt.Println("migrate down: done") return nil case "steps": if len(args) < 2 { return fmt.Errorf("steps 缺少步数参数\n%s", usage) } n, err := strconv.Atoi(args[1]) if err != nil { return fmt.Errorf("steps 参数必须为整数: %w", err) } if err := migration.Steps(mysqlSetting, n); err != nil { return err } fmt.Printf("migrate steps %d: done\n", n) return nil case "version": version, dirty, err := migration.Version(mysqlSetting) if err != nil { return err } fmt.Printf("version: %d, dirty: %t\n", version, dirty) return nil case "force": if len(args) < 2 { return fmt.Errorf("force 缺少版本号参数\n%s", usage) } v, err := strconv.Atoi(args[1]) if err != nil { return fmt.Errorf("force 参数必须为整数: %w", err) } if err := migration.Force(mysqlSetting, v); err != nil { return err } fmt.Printf("migrate force %d: done\n", v) return nil default: return fmt.Errorf("unknown command: %s\n%s", args[0], usage) } } // loadMysqlSetting 读取 configs/config.yaml 的 Mysql 配置段。 func loadMysqlSetting() (*setting.MysqlSettingS, error) { s, err := setting.NewSetting() if err != nil { return nil, fmt.Errorf("read config: %w", err) } var mysqlSetting setting.MysqlSettingS if err := s.ReadSection("Mysql", &mysqlSetting); err != nil { return nil, fmt.Errorf("read Mysql section: %w", err) } if mysqlSetting.DBName == "" { return nil, fmt.Errorf("Mysql.DBName is empty in configs/config.yaml") } return &mysqlSetting, nil }