package database import ( "carrotskin/internal/model" "carrotskin/pkg/config" "fmt" "sync" "go.uber.org/zap" "gorm.io/gorm" ) var ( // dbInstance 全局数据库实例 dbInstance *gorm.DB // once 确保只初始化一次 once sync.Once // initError 初始化错误 initError error ) // Init 初始化数据库连接(线程安全,只会执行一次) func Init(cfg config.DatabaseConfig, logger *zap.Logger) error { once.Do(func() { dbInstance, initError = New(cfg) if initError != nil { logger.Error("数据库初始化失败", zap.Error(initError)) return } logger.Info("数据库连接成功") }) return initError } // GetDB 获取数据库实例(线程安全) func GetDB() (*gorm.DB, error) { if dbInstance == nil { return nil, fmt.Errorf("数据库未初始化,请先调用 database.Init()") } return dbInstance, nil } // MustGetDB 获取数据库实例,如果未初始化则panic func MustGetDB() *gorm.DB { db, err := GetDB() if err != nil { panic(err) } return db } // AutoMigrate 自动迁移数据库表结构 func AutoMigrate(logger *zap.Logger) error { db, err := GetDB() if err != nil { return fmt.Errorf("获取数据库实例失败: %w", err) } logger.Info("开始执行数据库迁移...") // 迁移所有表 - 注意顺序:先创建被引用的表,再创建引用表 // 使用分批迁移,避免某些表的问题影响其他表 tables := []interface{}{ // 用户相关表(先创建,因为其他表可能引用它) &model.User{}, &model.UserPointLog{}, &model.UserLoginLog{}, // 档案相关表 &model.Profile{}, // 材质相关表 &model.Texture{}, &model.UserTextureFavorite{}, &model.TextureDownloadLog{}, // 认证相关表 &model.Client{}, // Client表用于管理Token版本 // Yggdrasil相关表(在User之后创建,因为它引用User) &model.Yggdrasil{}, // 审计日志表 &model.AuditLog{}, // Casbin权限规则表 &model.CasbinRule{}, } // 批量迁移表 if err := db.AutoMigrate(tables...); err != nil { logger.Error("数据库迁移失败", zap.Error(err)) return fmt.Errorf("数据库迁移失败: %w", err) } logger.Info("数据库迁移完成") return nil } // Close 关闭数据库连接 func Close() error { if dbInstance == nil { return nil } sqlDB, err := dbInstance.DB() if err != nil { return err } return sqlDB.Close() }