Files
kefu_cloud/server/internal/model/db.go
T

140 lines
3.1 KiB
Go

package model
import (
"database/sql"
"log"
"os"
"strconv"
"time"
"gorm.io/driver/postgres"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
var DB *gorm.DB
// DBPoolConfig 数据库连接池配置
type DBPoolConfig struct {
MaxOpenConns int
MaxIdleConns int
ConnMaxLifetime time.Duration
ConnMaxIdleTime time.Duration
}
// DefaultDBPoolConfig 返回连接池配置,优先读取环境变量,缺省提供生产合理的默认值
func DefaultDBPoolConfig() DBPoolConfig {
maxOpen := getEnvInt("DB_MAX_OPEN_CONNS", 50)
maxIdle := getEnvInt("DB_MAX_IDLE_CONNS", 10)
lifetimeMin := getEnvInt("DB_CONN_MAX_LIFETIME_MINUTES", 60)
idleTimeMin := getEnvInt("DB_CONN_MAX_IDLE_MINUTES", 15)
if maxOpen <= 0 {
maxOpen = 50
}
if maxIdle <= 0 {
maxIdle = 10
}
if maxIdle > maxOpen {
maxIdle = maxOpen
}
return DBPoolConfig{
MaxOpenConns: maxOpen,
MaxIdleConns: maxIdle,
ConnMaxLifetime: time.Duration(lifetimeMin) * time.Minute,
ConnMaxIdleTime: time.Duration(idleTimeMin) * time.Minute,
}
}
// ApplyPoolConfig 将连接池参数应用至底层 *sql.DB
func ApplyPoolConfig(sqlDB *sql.DB, cfg DBPoolConfig) {
if sqlDB == nil {
return
}
sqlDB.SetMaxOpenConns(cfg.MaxOpenConns)
sqlDB.SetMaxIdleConns(cfg.MaxIdleConns)
sqlDB.SetConnMaxLifetime(cfg.ConnMaxLifetime)
sqlDB.SetConnMaxIdleTime(cfg.ConnMaxIdleTime)
}
// BuildGormLogger 根据 GIN_MODE 区分日志策略:生产模式仅记录慢查询与错误,避免全量 SQL 撑满磁盘
func BuildGormLogger() logger.Interface {
mode := os.Getenv("GIN_MODE")
if mode == "release" {
return logger.New(
log.New(os.Stdout, "\r\n", log.LstdFlags),
logger.Config{
SlowThreshold: 200 * time.Millisecond,
LogLevel: logger.Warn,
IgnoreRecordNotFoundError: true,
Colorful: false,
},
)
}
return logger.Default.LogMode(logger.Info)
}
func getEnvInt(key string, fallback int) int {
if v := os.Getenv(key); v != "" {
if n, err := strconv.Atoi(v); err == nil {
return n
}
}
return fallback
}
func InitDB(dsn string) {
var err error
DB, err = gorm.Open(postgres.Open(dsn), &gorm.Config{
Logger: BuildGormLogger(),
})
if err != nil {
log.Fatalf("数据库连接失败: %v", err)
}
sqlDB, err := DB.DB()
if err != nil {
log.Fatalf("获取底层数据库连接失败: %v", err)
}
poolCfg := DefaultDBPoolConfig()
ApplyPoolConfig(sqlDB, poolCfg)
err = Migrate(DB)
if err != nil {
log.Fatalf("数据库迁移失败: %v", err)
}
log.Printf("数据库连接成功并完成迁移 [pool: max_open=%d, max_idle=%d, lifetime=%v, idletime=%v]",
poolCfg.MaxOpenConns, poolCfg.MaxIdleConns, poolCfg.ConnMaxLifetime, poolCfg.ConnMaxIdleTime)
}
func Migrate(db *gorm.DB) error {
return db.AutoMigrate(
&Tenant{},
&User{},
&Channel{},
&Customer{},
&CustomerTag{},
&CustomerContact{},
&BlacklistEntry{},
&Session{},
&VisitorPageView{},
&Message{},
&SessionEvent{},
&Category{},
&KnowledgeEntry{},
&QuickReply{},
&QuickReplyUserUsage{},
&Plan{},
&OperationLog{},
&Announcement{},
&TenantSetting{},
&Role{},
&Permission{},
&RolePermission{},
&RoleDataScope{},
)
}