143 lines
3.9 KiB
Go
143 lines
3.9 KiB
Go
|
package db
|
|||
|
|
|||
|
import (
|
|||
|
"admin/internal/errcode"
|
|||
|
"admin/internal/global"
|
|||
|
"admin/lib/xlog"
|
|||
|
"fmt"
|
|||
|
mysqlDriver "github.com/go-sql-driver/mysql"
|
|||
|
"gorm.io/driver/mysql"
|
|||
|
"gorm.io/driver/sqlite"
|
|||
|
"gorm.io/gorm"
|
|||
|
"sync"
|
|||
|
"time"
|
|||
|
)
|
|||
|
|
|||
|
var (
|
|||
|
globalTables []any
|
|||
|
locker sync.Mutex
|
|||
|
)
|
|||
|
|
|||
|
func RegisterTableModels(models ...any) {
|
|||
|
locker.Lock()
|
|||
|
defer locker.Unlock()
|
|||
|
globalTables = append(globalTables, models...)
|
|||
|
}
|
|||
|
|
|||
|
func NewDB(dbType, dbAddr, dbName, dbUser, dbPass string) (db *gorm.DB, err error) {
|
|||
|
switch dbType {
|
|||
|
case "sqlite":
|
|||
|
db, err = gorm.Open(sqlite.Open(dbName+".db"), &gorm.Config{})
|
|||
|
if err != nil {
|
|||
|
return nil, err
|
|||
|
}
|
|||
|
case "mysql":
|
|||
|
dsn := fmt.Sprintf("%v:%v@tcp(%v)/%v?charset=utf8mb4&parseTime=True&loc=Local", dbUser, dbPass, dbAddr, dbName)
|
|||
|
dsnWithoutDB := fmt.Sprintf("%v:%v@tcp(%v)/?charset=utf8mb4&parseTime=True&loc=Local", dbUser, dbPass, dbAddr)
|
|||
|
db, err = createDBAndGuaranteeMigrate(dsnWithoutDB, dsn, globalTables)
|
|||
|
}
|
|||
|
global.GLOB_DB = db
|
|||
|
return db, nil
|
|||
|
}
|
|||
|
|
|||
|
func createDBAndGuaranteeMigrate(dsnWithoutDb, dsn string, tables []any) (*gorm.DB, error) {
|
|||
|
mysqlDriverConf, err := mysqlDriver.ParseDSN(dsn)
|
|||
|
if err != nil {
|
|||
|
return nil, fmt.Errorf("parse dsn:%v error:%v", dsn, err)
|
|||
|
}
|
|||
|
dbName := mysqlDriverConf.DBName
|
|||
|
_, err = tryCreateDB(dbName, dsnWithoutDb)
|
|||
|
if err != nil {
|
|||
|
xlog.Fatalf(err)
|
|||
|
return nil, err
|
|||
|
}
|
|||
|
|
|||
|
driverConf := mysql.Config{
|
|||
|
DSN: dsn,
|
|||
|
DontSupportRenameColumn: true,
|
|||
|
//SkipInitializeWithVersion: false, // 根据数据库版本自动配置
|
|||
|
}
|
|||
|
dialector := mysql.New(driverConf)
|
|||
|
|
|||
|
//slowLogger := logger.New(
|
|||
|
// syslog.New(xlog.GetGlobalWriter(), "\n", syslog.LstdFlags),
|
|||
|
// logger.Config{
|
|||
|
// // 设定慢查询时间阈值为 默认值:200 * time.Millisecond
|
|||
|
// SlowThreshold: 200 * time.Millisecond,
|
|||
|
// // 设置日志级别
|
|||
|
// LogLevel: logger.Warn,
|
|||
|
// Colorful: true,
|
|||
|
// },
|
|||
|
//)
|
|||
|
|
|||
|
db, err := gorm.Open(dialector, &gorm.Config{
|
|||
|
Logger: &gormLogger{},
|
|||
|
PrepareStmt: false, // 关闭缓存sql语句功能,因为后续use db会报错,这个缓存会无限存储可能导致内存泄露
|
|||
|
//SkipDefaultTransaction: true, // 跳过默认事务
|
|||
|
})
|
|||
|
if err != nil {
|
|||
|
return nil, fmt.Errorf("failed to connect to mysql:%v", err)
|
|||
|
}
|
|||
|
|
|||
|
sqlDB, _ := db.DB()
|
|||
|
sqlDB.SetMaxIdleConns(10)
|
|||
|
sqlDB.SetMaxOpenConns(50)
|
|||
|
sqlDB.SetConnMaxIdleTime(time.Minute * 5)
|
|||
|
sqlDB.SetConnMaxLifetime(time.Minute * 10)
|
|||
|
|
|||
|
if len(tables) > 0 {
|
|||
|
err = autoMigrate(db, tables...)
|
|||
|
if err != nil {
|
|||
|
xlog.Fatalf(err)
|
|||
|
return nil, fmt.Errorf("automigrate error:%v", err)
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//addMetricsCollection(db, strconv.Itoa(int(serverId)), dbName)
|
|||
|
return db, nil
|
|||
|
}
|
|||
|
|
|||
|
func tryCreateDB(dbName, dsn string) (string, error) {
|
|||
|
driverConf := mysql.Config{
|
|||
|
DSN: dsn,
|
|||
|
DontSupportRenameColumn: true,
|
|||
|
//SkipInitializeWithVersion: false, // 根据数据库版本自动配置
|
|||
|
}
|
|||
|
dialector := mysql.New(driverConf)
|
|||
|
|
|||
|
db, err := gorm.Open(dialector, &gorm.Config{
|
|||
|
PrepareStmt: false, // 关闭缓存sql语句功能,因为后续use db会报错,这个缓存会无限存储可能导致内存泄露
|
|||
|
//SkipDefaultTransaction: true, // 跳过默认事务
|
|||
|
})
|
|||
|
if err != nil {
|
|||
|
return "", fmt.Errorf("failed to connect to mysql:%v", err)
|
|||
|
}
|
|||
|
|
|||
|
// 检查数据库是否存在
|
|||
|
var count int
|
|||
|
db.Raw("SELECT COUNT(*) FROM information_schema.schemata WHERE schema_name = ?", dbName).Scan(&count)
|
|||
|
if count == 0 {
|
|||
|
// 数据库不存在,创建它
|
|||
|
sql := fmt.Sprintf(`create database if not exists %s default charset utf8mb4 collate utf8mb4_unicode_ci`,
|
|||
|
dbName)
|
|||
|
if e := db.Exec(sql).Error; e != nil {
|
|||
|
return "", fmt.Errorf("failed to create database:%v", e)
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
sqlDb, _ := db.DB()
|
|||
|
sqlDb.Close()
|
|||
|
|
|||
|
return dbName, nil
|
|||
|
}
|
|||
|
|
|||
|
func autoMigrate(db *gorm.DB, tables ...interface{}) error {
|
|||
|
// 这个函数是在InitConn之后调用的
|
|||
|
|
|||
|
// 初始化表
|
|||
|
if err := db.AutoMigrate(tables...); err != nil {
|
|||
|
return errcode.New(errcode.DBError, "failed to init tables", err)
|
|||
|
}
|
|||
|
return nil
|
|||
|
}
|