2026-08-10 02:40:14 +08:00
|
|
|
// migrate-sqlite-to-mysql 把历史 SQLite v8 数据一次性导入空的 MySQL 8 数据库。
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"flag"
|
|
|
|
|
"fmt"
|
|
|
|
|
"log"
|
|
|
|
|
|
|
|
|
|
"cmautobuy/admin/config"
|
|
|
|
|
"cmautobuy/admin/repository"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
|
sourcePath := flag.String("source", "", "历史 admin.db 路径(必填,只读打开)")
|
|
|
|
|
dryRun := flag.Bool("dry-run", false, "只检查源库和空目标库,不写入")
|
|
|
|
|
execute := flag.Bool("execute", false, "执行一次性迁移")
|
|
|
|
|
verifyOnly := flag.Bool("verify-only", false, "只核对已迁移的 MySQL 与 SQLite")
|
|
|
|
|
flag.Parse()
|
|
|
|
|
|
|
|
|
|
if *sourcePath == "" {
|
|
|
|
|
log.Fatal("必须提供 --source 指向历史 admin.db")
|
|
|
|
|
}
|
|
|
|
|
modeCount := 0
|
|
|
|
|
for _, enabled := range []bool{*dryRun, *execute, *verifyOnly} {
|
|
|
|
|
if enabled {
|
|
|
|
|
modeCount++
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if modeCount != 1 {
|
|
|
|
|
log.Fatal("必须且只能选择 --dry-run、--execute、--verify-only 其中一个")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
source, err := repository.OpenLegacySQLiteReadOnly(*sourcePath)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
defer source.Close()
|
|
|
|
|
|
2026-08-10 09:24:04 +08:00
|
|
|
databaseConfig, err := config.LoadDatabase()
|
2026-08-10 02:40:14 +08:00
|
|
|
if err != nil {
|
|
|
|
|
log.Fatalf("读取 MySQL 配置失败: %v", err)
|
|
|
|
|
}
|
|
|
|
|
target, err := repository.OpenMySQL(databaseConfig)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
defer target.Close()
|
|
|
|
|
if err := repository.MigrateMySQL(target); err != nil {
|
|
|
|
|
log.Fatalf("准备 MySQL schema 失败: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var summary *repository.SQLiteMigrationSummary
|
|
|
|
|
switch {
|
|
|
|
|
case *verifyOnly:
|
|
|
|
|
summary, err = repository.VerifySQLiteToMySQL(source, target)
|
|
|
|
|
case *dryRun:
|
|
|
|
|
summary, err = repository.MigrateSQLiteToMySQL(source, target, true)
|
|
|
|
|
default:
|
|
|
|
|
summary, err = repository.MigrateSQLiteToMySQL(source, target, false)
|
|
|
|
|
}
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mode := "迁移完成并核对通过"
|
|
|
|
|
if *dryRun {
|
|
|
|
|
mode = "演练检查通过,未写入数据"
|
|
|
|
|
} else if *verifyOnly {
|
|
|
|
|
mode = "迁移数据核对通过,未写入数据"
|
|
|
|
|
}
|
|
|
|
|
fmt.Println(mode)
|
|
|
|
|
for _, table := range repository.SortedMigrationSummary(summary) {
|
|
|
|
|
fmt.Printf("%-28s %d\n", table.Name, table.Count)
|
|
|
|
|
}
|
|
|
|
|
}
|