From 658a9cb5800241908f7d05be25d5d0736ed11c30 Mon Sep 17 00:00:00 2001 From: Sakurasan <26715255+Sakurasan@users.noreply.github.com> Date: Sat, 29 Aug 2026 12:46:52 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20SQLite=20=E8=BF=81=E7=A7=BB=E5=8A=A0?= =?UTF-8?q?=E7=89=88=E6=9C=AC=E9=94=81=EF=BC=8C=E6=B6=88=E9=99=A4=E6=AF=8F?= =?UTF-8?q?=E6=AC=A1=E5=90=AF=E5=8A=A8=E5=85=A8=E9=87=8F=E9=87=8D=E5=BB=BA?= =?UTF-8?q?=E8=A1=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GORM sqlite AutoMigrate 对已有表判定不收敛(实测已迁移库再跑 仍触发 12 次表重建),SQLite 无在线 ALTER,每次重建走 CREATE __temp + INSERT SELECT + DROP 全表拷贝;usage_logs 含 raw_request/raw_response 大文本,一轮 40~80s,生产每次重启 重演导致启动数分钟。 - 新增 schemaVersion 常量,PRAGMA user_version 记录已迁移版本 - 版本达标跳过 AutoMigrate 秒开;旧库首次升级迁移一次写版本 - postgres 不受影响(支持 ALTER,保持原行为) - 维护约定:改表结构须递增 schemaVersion --- server/internal/store/db.go | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/server/internal/store/db.go b/server/internal/store/db.go index b7c8922..23776fa 100644 --- a/server/internal/store/db.go +++ b/server/internal/store/db.go @@ -1,6 +1,7 @@ package store import ( + "fmt" "log" "os" "path/filepath" @@ -11,6 +12,12 @@ import ( gormlogger "gorm.io/gorm/logger" ) +// schemaVersion 当前 schema 版本。struct 变更(加列/改列/删列)时递增, +// 触发一次 AutoMigrate 并把新版本写入库(SQLite 用 PRAGMA user_version)。 +// AutoMigrate 对已有表的列判定不收敛(每次都重建表:CREATE __temp + INSERT SELECT + DROP), +// 大表上一次重建数十秒且每次重启重演,所以之后版本未变就直接跳过。 +const schemaVersion = 1 + // Open 打开数据库连接并自动迁移。 // 开发默认 SQLite(dsn 支持 file:...?_journal_mode=WAL),生产可切 postgres。 func Open(driver, dsn string) (*gorm.DB, error) { @@ -33,13 +40,33 @@ func Open(driver, dsn string) (*gorm.DB, error) { return nil, err } + if driver != "postgres" && currentSQLiteVersion(db) >= schemaVersion { + log.Printf("store: connected driver=%s (schema up-to-date v%d, skip migrate)", driver, schemaVersion) + return db, nil + } + if err := db.AutoMigrate(AllModels()...); err != nil { return nil, err } - log.Printf("store: connected driver=%s (migrated)", driver) + if driver != "postgres" { + setSQLiteVersion(db, schemaVersion) + } + log.Printf("store: connected driver=%s (migrated, schema v%d)", driver, schemaVersion) return db, nil } +// currentSQLiteVersion 读取 PRAGMA user_version。 +func currentSQLiteVersion(db *gorm.DB) int { + var v int + db.Raw("PRAGMA user_version").Scan(&v) + return v +} + +// setSQLiteVersion 写入 PRAGMA user_version。 +func setSQLiteVersion(db *gorm.DB, v int) { + db.Exec(fmt.Sprintf("PRAGMA user_version = %d", v)) +} + // sqliteDir 提取 SQLite DSN 中的目录部分(忽略 file: 前缀与查询参数)。 func sqliteDir(dsn string) string { d := dsn