初始化

This commit is contained in:
李琦
2026-08-14 13:17:03 +08:00
commit 2f5ce02608
72 changed files with 11132 additions and 0 deletions

39
internal/database/db.go Normal file
View File

@@ -0,0 +1,39 @@
// Package database 负责数据库连接初始化与 GORM 实例管理
package database
import (
"fmt"
"time"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"nl-game-api-gin/internal/config"
)
// DB 全局数据库实例,Init 成功后可直接使用
var DB *gorm.DB
// Init 连接 MySQL 并配置连接池
func Init() error {
db, err := gorm.Open(mysql.Open(config.C.DSN()), &gorm.Config{
// 只打印慢查询与错误 SQL,避免日志刷屏
Logger: logger.Default.LogMode(logger.Warn),
// dev 自动建表时不生成物理外键约束,与 sql/init.sql 的手写表结构保持一致
DisableForeignKeyConstraintWhenMigrating: true,
})
if err != nil {
return fmt.Errorf("连接 MySQL 失败: %w", err)
}
sqlDB, err := db.DB()
if err != nil {
return fmt.Errorf("获取底层连接池失败: %w", err)
}
// 连接池参数:空闲 10、最大 100、连接最长存活 1 小时
sqlDB.SetMaxIdleConns(10)
sqlDB.SetMaxOpenConns(100)
sqlDB.SetConnMaxLifetime(time.Hour)
DB = db
return nil
}

View File

@@ -0,0 +1,68 @@
// dev 环境自动建表(仅 go run 生效)
//
// 安全约定:表结构迁移只允许发生在开发模式(go run 启动)。
// go build 打包出的二进制启动时绝不会执行任何迁移——生产库的结构
// 变更一律通过 sql/ 目录下的脚本人工执行,防止 GORM 自动改表出问题。
//
// dev 下也只做最保守的一件事:补建"库里不存在的表"。
// 已存在的表一律不动(不加列、不加索引),因为手写 SQL 的索引命名
// (uk_username 等)与 GORM 默认命名不同,全量 AutoMigrate 会重复建索引。
package database
import (
"log"
"os"
"strings"
"nl-game-api-gin/internal/model"
)
// IsDevRun 判断当前进程是否由 go run 启动:
// go run 会先把临时二进制编译到 go-build 缓存目录(如 %TEMP%\go-buildXXXX)再运行,
// 而 go build 的产物路径不含该特征,因此打包后的服务永远不会命中 dev 分支。
func IsDevRun() bool {
exe, err := os.Executable()
if err != nil {
return false
}
return strings.Contains(exe, "go-build")
}
// AutoMigrateMissing 遍历全部 GORM 模型,为缺失的表建表(含索引),已存在的表跳过。
// 新增 model 后在下方清单登记一行,dev 启动即可自动建表;种子数据仍需执行对应 SQL 脚本。
func AutoMigrateMissing() error {
models := []interface{ TableName() string }{
// 用户与登录
&model.User{}, &model.LoginLog{},
// 游戏与对局记录
&model.Game{}, &model.GameRecord{}, &model.BattleRecord{},
// 积分与签到
&model.PointRecord{}, &model.SignIn{},
// 商城:购物车 / 订单 / 已购游戏 / 道具
&model.Cart{}, &model.Order{}, &model.OrderItem{}, &model.UserGame{}, &model.Prop{}, &model.UserProp{},
// 社交:好友 / 私聊
&model.Friend{}, &model.ChatMessage{},
// 主题与站点配置
&model.Theme{}, &model.SiteConfig{},
// VIP 等级
&model.VipLevel{},
// 关卡进度 / 云存档 / 皮肤
&model.GameProgress{}, &model.GameSave{},
&model.GameSkin{}, &model.UserSkin{},
}
created := 0
for _, m := range models {
if DB.Migrator().HasTable(m) {
continue
}
if err := DB.Migrator().CreateTable(m); err != nil {
return err
}
created++
log.Printf("[dev迁移] 已创建缺失表 %s(种子数据请执行 sql/ 对应脚本)", m.TableName())
}
if created == 0 {
log.Println("[dev迁移] 全部表已存在,无需创建")
}
return nil
}