From 93abf81e40cdc87bc96d626ab38a062d9d9e40ed Mon Sep 17 00:00:00 2001 From: "Logan.Li" Date: Mon, 14 Sep 2026 07:59:36 +0000 Subject: [PATCH] =?UTF-8?q?fix(database):=20=E4=BF=AE=E5=A4=8D=E7=A9=BA?= =?UTF-8?q?=E5=BA=93=E5=9F=BA=E7=BA=BF=E8=BF=81=E7=A7=BB=E5=9B=A0=E7=B4=A2?= =?UTF-8?q?=E5=BC=95=E5=91=BD=E5=90=8D=E4=B8=8D=E4=B8=80=E8=87=B4=E8=80=8C?= =?UTF-8?q?=E5=A4=B1=E8=B4=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GORM 1.30 AutoMigrate 对已存在表的唯一索引执行 `DROP INDEX uni_<表>_<列>`, 而建表阶段用的是 idx_ 前缀,索引名永不匹配,空库执行基线必然以 Error 1091 (Can't DROP ...; check that column/key exists) 失败。 - 新增 indexNamedNaming,令 UniqueName 复用 IndexName 的 idx_ 命名 - BootstrapSchema 改为一次性 AutoMigrate(allModels...), 让 GORM 在外键依赖排序生效(如 asset_cloud_regions 先于 asset_servers) // Logan.Li --- backend/pkg/database/database.go | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/backend/pkg/database/database.go b/backend/pkg/database/database.go index d0b7888..a0a09bd 100644 --- a/backend/pkg/database/database.go +++ b/backend/pkg/database/database.go @@ -14,6 +14,7 @@ import ( "gorm.io/driver/postgres" "gorm.io/gorm" "gorm.io/gorm/logger" + "gorm.io/gorm/schema" ) // New 创建数据库连接 @@ -50,7 +51,8 @@ func New(cfg config.DatabaseConfig) (*gorm.DB, error) { } db, err := gorm.Open(dialector, &gorm.Config{ - Logger: logger.Default.LogMode(logger.Silent), + Logger: logger.Default.LogMode(logger.Silent), + NamingStrategy: indexNamedNaming{}, }) if err != nil { return nil, err @@ -69,6 +71,19 @@ func New(cfg config.DatabaseConfig) (*gorm.DB, error) { return db, nil } +// indexNamedNaming 让唯一索引与普通索引使用同一套命名规则(idx_ 前缀)。 +// GORM 1.30 的 AutoMigrate 在表已存在时会对唯一索引列执行 `DROP INDEX uni_<表>_<列>` +// (NamingStrategy.UniqueName 用 uni_ 前缀),而建表实际使用 `idx_<表>_<列>`, +// 索引名永远不匹配,空库执行基线必然以 1091 失败。 // Logan.Li +type indexNamedNaming struct { + schema.NamingStrategy +} + +// UniqueName 保持与 IndexName 一致,避免 AutoMigrate 误删不存在的唯一索引。 +func (n indexNamedNaming) UniqueName(table, column string) string { + return n.NamingStrategy.IndexName(table, column) +} + // BootstrapSchema 为空数据库创建初始基线结构。 // 该函数只能由显式的 `aiops migrate up` 调用,服务启动路径禁止调用。 // Logan.Li func BootstrapSchema(db *gorm.DB) error { @@ -177,10 +192,10 @@ func BootstrapSchema(db *gorm.DB) error { &model.TraceDataSource{}, // 链路追踪数据源 Jaeger/Tempo // Logan.Li } - for _, m := range allModels { - if err := db.AutoMigrate(m); err != nil { - return fmt.Errorf("创建初始基线表失败 (%T): %w", m, err) - } + // 必须一次性传入全部模型:GORM 只在单次调用内做外键依赖排序 + // (如 asset_cloud_regions 必须在 asset_servers 之前建表),逐个建表会踩外键顺序问题。 // Logan.Li + if err := db.AutoMigrate(allModels...); err != nil { + return fmt.Errorf("创建初始基线表失败: %w", err) } return nil }