This commit is contained in:
kzkzzzz
2025-03-22 01:24:57 +08:00
parent 197476e805
commit 7e0bf82418
22 changed files with 2291 additions and 919 deletions

View File

@@ -1,150 +1,203 @@
package mymysql
import (
"database/sql"
"fmt"
"git.makemake.in/kzkzzzz/mycommon/mylog"
"git.makemake.in/kzkzzzz/mycommon/myconf"
driverMysql "github.com/go-sql-driver/mysql"
"github.com/google/uuid"
"gorm.io/driver/mysql"
"gorm.io/gorm"
gormLogger "gorm.io/gorm/logger"
"gorm.io/gorm/logger"
"log"
"os"
"sync"
"time"
)
const DefaultKey = "default"
const (
DefaultInstance = "mysql"
)
type MysqlDb struct {
*gorm.DB
SqlDB *sql.DB
gormConfig *gorm.Config
disablePing bool
}
type Conf struct {
Dsn string
MaxOpenConn int // 最大连接数
MaxIdleConn int // 最大空闲连接数
MaxIdleTime string // 空闲时间
MaxLifeTime string // 连接最大有效时间
Debug bool
LogSqlSlowTimeMs int
LogDisableColor bool
}
var (
DefaultConfig = &Config{
Dsn: "root:root@tcp(127.0.0.1:3306)/?loc=Local&charset=utf8mb4&parseTime=true",
MaxOpenConn: 32,
MaxIdleConn: 8,
MaxLifeTime: "4h",
MaxIdleTime: "15m",
Debug: true,
GormLogger: gormLogger.Default.LogMode(gormLogger.Info),
}
instanceMap = make(map[string]*gorm.DB)
instanceMap = &sync.Map{}
)
type (
Config struct {
Dsn string
MaxOpenConn int
MaxIdleConn int
MaxIdleTime string
MaxLifeTime string
Debug bool
GormLogger gormLogger.Interface
}
)
func DB(key ...string) *gorm.DB {
var key0 string
if len(key) > 0 {
key0 = key[0]
func GetDb(name ...string) *MysqlDb {
var instanceName string
if len(name) > 0 {
instanceName = name[0]
} else {
key0 = DefaultKey
instanceName = DefaultInstance
}
instance, ok := instanceMap[key0]
v, ok := instanceMap.Load(instanceName)
if !ok {
panic(fmt.Errorf("mysql %s not config", key0))
panic(fmt.Errorf("mysql instance [%s] not init", instanceName))
}
return instance
return v.(*MysqlDb)
}
func InitDefault(config *Config) {
Init(DefaultKey, config)
}
func Init(key string, config *Config) {
db, err := New(config)
// InitDb 初始化全局默认db
func InitDb(config *myconf.Config, opts ...Opt) {
client, err := NewDb(DefaultInstance, config, opts...)
if err != nil {
panic(err)
}
instanceMap[key] = db
instanceMap.Store(DefaultInstance, client)
}
func New(config *Config) (*gorm.DB, error) {
var (
maxLifeTime, _ = time.ParseDuration(DefaultConfig.MaxLifeTime)
maxIdleTime, _ = time.ParseDuration(DefaultConfig.MaxIdleTime)
logger gormLogger.Interface
)
if config.MaxOpenConn <= 0 {
config.MaxOpenConn = DefaultConfig.MaxOpenConn
}
if config.MaxIdleConn <= 0 {
config.MaxIdleConn = DefaultConfig.MaxIdleConn
}
if config.MaxLifeTime != "" {
t, err := time.ParseDuration(config.MaxLifeTime)
if err != nil {
return nil, fmt.Errorf("parse MaxLifeTime err: %s\n", err)
}
maxLifeTime = t
}
if config.MaxIdleTime != "" {
t, err := time.ParseDuration(config.MaxIdleTime)
if err != nil {
return nil, fmt.Errorf("parse MaxIdleTime err: %s\n", err)
}
maxIdleTime = t
}
if config.GormLogger == nil {
level := gormLogger.Warn
if config.Debug {
level = gormLogger.Info
}
logger = DefaultGormLogger(level)
}
db, err := gorm.Open(mysql.Open(config.Dsn), &gorm.Config{
SkipDefaultTransaction: true,
Logger: logger,
})
// InitDbInstance 初始化全局的db
func InitDbInstance(instanceName string, config *myconf.Config, opts ...Opt) {
client, err := NewDb(instanceName, config, opts...)
if err != nil {
return nil, fmt.Errorf("connect mysql err: %s", err)
panic(err)
}
sqlDb, _ := db.DB()
instanceMap.Store(instanceName, client)
}
sqlDb.SetMaxOpenConns(config.MaxOpenConn)
sqlDb.SetMaxIdleConns(config.MaxIdleConn)
sqlDb.SetConnMaxLifetime(maxLifeTime)
sqlDb.SetConnMaxIdleTime(maxIdleTime)
func NewDb(instanceName string, config *myconf.Config, opts ...Opt) (*MysqlDb, error) {
cf := &Conf{Debug: true}
err := config.UnmarshalKey(instanceName, &cf)
if err != nil {
return nil, err
}
db, err := NewDbFromConf(cf, opts...)
if err != nil {
return nil, err
}
instanceMap.Store(instanceName, db)
return db, nil
}
func NewDbFromConf(cf *Conf, opts ...Opt) (*MysqlDb, error) {
parseDsn, err := driverMysql.ParseDSN(cf.Dsn)
if err != nil {
return nil, fmt.Errorf("mysql parse dsn error: %s", err)
}
db := &MysqlDb{}
for _, opt := range opts {
opt(db)
}
if db.gormConfig == nil {
db.gormConfig = &gorm.Config{
SkipDefaultTransaction: true,
}
lCfg := logger.Config{
SlowThreshold: 200 * time.Millisecond,
LogLevel: logger.Warn,
IgnoreRecordNotFoundError: false,
Colorful: true,
}
if cf.LogSqlSlowTimeMs > 0 {
lCfg.SlowThreshold = time.Duration(cf.LogSqlSlowTimeMs) * time.Millisecond
}
if cf.LogDisableColor {
lCfg.Colorful = false
}
l := newGormLogger(lCfg)
if cf.Debug {
db.gormConfig.Logger = l.LogMode(logger.Info)
} else {
db.gormConfig.Logger = l
}
}
gormDB, err := gorm.Open(mysql.Open(cf.Dsn), db.gormConfig)
if err != nil {
return nil, err
}
sqlDB, err := gormDB.DB()
if err != nil {
return nil, err
}
if db.disablePing == false {
err = sqlDB.Ping()
if err != nil {
return nil, err
}
}
if cf.MaxOpenConn <= 0 {
cf.MaxOpenConn = 1024
}
if cf.MaxIdleConn <= 0 {
// 默认最大空闲数等于最大连接数
cf.MaxIdleConn = cf.MaxOpenConn
}
if cf.MaxIdleTime == "" {
cf.MaxIdleTime = "10m"
}
sqlDB.SetMaxOpenConns(cf.MaxOpenConn)
sqlDB.SetMaxIdleConns(cf.MaxIdleConn)
if dv, err := time.ParseDuration(cf.MaxIdleTime); err != nil {
return nil, fmt.Errorf("parse MaxIdleTime err: %s", err)
} else {
sqlDB.SetConnMaxIdleTime(dv)
}
// max life time默认暂不设置, 使用idle time控制即可
if cf.MaxLifeTime != "" {
if dv, err := time.ParseDuration(cf.MaxLifeTime); err != nil {
return nil, fmt.Errorf("parse MaxLifeTime err: %s", err)
} else {
sqlDB.SetConnMaxLifetime(dv)
}
}
db.DB = gormDB
db.SqlDB = sqlDB
instanceMap.Store(uuid.New().String(), db)
log.Printf("connect db success [addr:%s - db:%s]", parseDsn.Addr, parseDsn.DBName)
return db, nil
}
func DefaultGormLogger(level gormLogger.LogLevel) gormLogger.Interface {
return gormLogger.New(mylog.NewLogger("gorm", mylog.DefaultConfig), gormLogger.Config{
SlowThreshold: time.Second * 2,
Colorful: true,
IgnoreRecordNotFoundError: false,
ParameterizedQueries: false,
LogLevel: level,
func CloseAll() {
instanceMap.Range(func(k, v any) bool {
db, err := (v.(*MysqlDb)).DB.DB()
if err != nil {
db.Close()
}
return true
})
}
func NewGormLogger(writer gormLogger.Writer, gormLoggerConfig gormLogger.Config) gormLogger.Interface {
return gormLogger.New(writer, gormLoggerConfig)
}
func CloseDB(key string) {
db, _ := DB(key).DB()
db.Close()
}
func CloseAllDB() {
for _, v := range instanceMap {
db, _ := v.DB()
db.Close()
}
func newGormLogger(cfg logger.Config) logger.Interface {
return logger.New(log.New(os.Stdout, "\r\n", log.LstdFlags), cfg)
}