Files
slgserver/db/conn.go
2025-11-18 18:08:48 +08:00

156 lines
3.5 KiB
Go

package db
import (
"database/sql"
"errors"
"fmt"
_ "github.com/go-sql-driver/mysql"
"log/slog"
"os"
"path/filepath"
"slgserver/config"
"time"
"xorm.io/xorm"
"xorm.io/xorm/log"
)
var MasterDB *xorm.Engine
var logFileHandle *os.File
var (
ConnectDBErr = errors.New("connect db error")
UseDBErr = errors.New("use db error")
)
// TestDB 测试数据库
func TestDB() error {
mysqlConfig, err := config.GetSection("mysql")
if err != nil {
slog.Error("get mysql config error", "error", err)
panic(err)
}
tmpDns := fmt.Sprintf("%s:%s@tcp(%s:%s)/?charset=%s&parseTime=True&loc=Local",
mysqlConfig["user"],
mysqlConfig["password"],
mysqlConfig["host"],
mysqlConfig["port"],
mysqlConfig["charset"])
egnine, err := xorm.NewEngine("mysql", tmpDns)
if err != nil {
slog.Error("new engine error", "error", err)
panic(err)
}
defer egnine.Close()
// 测试数据库连接是否 OK
if err = egnine.Ping(); err != nil {
slog.Error("ping db error", "error", err)
return ConnectDBErr
}
_, err = egnine.Exec("use " + mysqlConfig["dbname"])
if err != nil {
slog.Error("use db error", "error", err)
// 使用参数化查询避免SQL注入风险
createDBQuery := fmt.Sprintf("CREATE DATABASE `%s` DEFAULT CHARACTER SET %s", mysqlConfig["dbname"], mysqlConfig["charset"])
_, err = egnine.Exec(createDBQuery)
if err != nil {
slog.Error("create database error", "error", err)
return UseDBErr
}
slog.Info("create database successfully")
}
// 初始化 MasterDB
return Init()
}
func Init() error {
mysqlConfig, err := config.GetSection("mysql")
if err != nil {
slog.Error("get mysql config error", "error", err)
return err
}
// 启动时就打开数据库连接
if err = initEngine(mysqlConfig); err != nil {
slog.Error("mysql is not open", "error", err)
return err
}
return nil
}
func fillDns(mysqlConfig map[string]string) string {
return fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=%s&parseTime=True&loc=Local",
mysqlConfig["user"],
mysqlConfig["password"],
mysqlConfig["host"],
mysqlConfig["port"],
mysqlConfig["dbname"],
mysqlConfig["charset"])
}
func initEngine(mysqlConfig map[string]string) error {
var err error
dns := fillDns(mysqlConfig)
MasterDB, err = xorm.NewEngine("mysql", dns)
if err != nil {
return err
}
// 数据库连接池配置,根据实际负载调整
maxIdle := config.GetInt("mysql.max_idle", 10) // 默认值从2提升到10
maxConn := config.GetInt("mysql.max_conn", 100) // 默认值从10提升到100
MasterDB.SetMaxIdleConns(maxIdle)
MasterDB.SetMaxOpenConns(maxConn)
// 设置连接最大生存时间,避免长时间连接导致的问题
MasterDB.SetConnMaxLifetime(time.Hour)
showSQL := config.GetBool("xorm.show_sql", false)
logLevel := config.GetInt("xorm.log_level", 1)
logFile := config.GetPath("xorm.log_file", "")
if logFile != "" {
if logFileHandle != nil {
logFileHandle.Close()
}
// 确保日志文件目录存在
if err := os.MkdirAll(filepath.Dir(logFile), 0755); err != nil {
return fmt.Errorf("failed to create log directory: %w", err)
}
f, err := os.OpenFile(logFile, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
if err != nil {
return err
}
logFileHandle = f
MasterDB.SetLogger(log.NewSimpleLogger(f))
}
MasterDB.SetLogLevel(log.LogLevel(logLevel))
MasterDB.ShowSQL(showSQL)
return nil
}
func StdMasterDB() *sql.DB {
return MasterDB.DB().DB
}
func Close() {
if MasterDB != nil {
MasterDB.Close()
}
if logFileHandle != nil {
logFileHandle.Close()
}
}