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() } }