database/client.go

307 lines
7.2 KiB
Go
Raw Permalink Normal View History

2022-05-15 11:27:28 +08:00
// Package mysql ...
//
// Description : mysql客户端
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 2021-03-01 9:20 下午
package mysql
import (
2022-06-11 18:25:00 +08:00
"errors"
2022-05-15 11:27:28 +08:00
"fmt"
2022-06-09 14:58:01 +08:00
"path/filepath"
"strings"
2022-06-05 19:49:45 +08:00
"sync"
2022-06-25 18:46:28 +08:00
"git.zhangdeman.cn/zhangdeman/util"
2022-05-15 11:27:28 +08:00
"git.zhangdeman.cn/zhangdeman/logger/wrapper"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
gormLogger "gorm.io/gorm/logger"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
2022-06-05 19:49:45 +08:00
var (
// Client mysql客户端
Client *client
)
func init() {
Client = &client{
lock: &sync.RWMutex{},
clientTable: make(map[string]*DBClient),
}
}
type client struct {
lock *sync.RWMutex
clientTable map[string]*DBClient
2022-06-12 18:26:19 +08:00
logger *zap.Logger
2022-06-05 19:49:45 +08:00
}
// AddWithConfigFile 使用文件生成新的客户端文件名去掉后缀作为flag
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 19:19 2022/6/5
2022-07-15 00:42:17 +08:00
func (c *client) AddWithConfigFile(cfgFilePath string, logInstance *zap.Logger) error {
2022-06-11 19:05:54 +08:00
var (
err error
cfg *cfgFile
dbClient *DBClient
)
if cfg, err = c.getCfg(cfgFilePath); nil != err {
return err
}
if nil == cfg {
// 不支持的配置文件格式
return nil
}
dbClient = &DBClient{
dbFlag: cfg.Flag,
2022-07-15 00:51:09 +08:00
loggerInstance: logInstance,
2022-06-11 19:05:54 +08:00
master: nil,
slave: nil,
extraFieldList: nil,
cfg: Mysql{},
}
2022-07-15 00:42:17 +08:00
if dbClient.master, err = c.GetDatabaseClient(cfg.Config.Master, logInstance); nil != err {
2022-06-11 19:05:54 +08:00
return err
}
2022-07-15 00:42:17 +08:00
if dbClient.slave, err = c.GetDatabaseClient(cfg.Config.Slave, logInstance); nil != err {
2022-06-11 19:05:54 +08:00
return err
}
c.lock.Lock()
c.clientTable[dbClient.dbFlag] = dbClient
c.lock.Unlock()
2022-06-05 19:49:45 +08:00
return nil
}
// BatchAddWithConfigDir 自动读取目录下配置文件, 生成客户端
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 19:19 2022/6/5
2022-07-15 00:42:17 +08:00
func (c *client) BatchAddWithConfigDir(cfgDir string, logInstance *zap.Logger) error {
2022-06-11 19:18:42 +08:00
filepathNames, _ := filepath.Glob(filepath.Join(cfgDir, "*"))
for i := range filepathNames {
2022-07-15 00:42:17 +08:00
if err := c.AddWithConfigFile(filepathNames[i], logInstance); nil != err {
2022-06-11 19:18:42 +08:00
return err
}
}
2022-06-05 19:49:45 +08:00
return nil
}
2022-06-11 18:25:00 +08:00
// getCfg 读取配置
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 18:05 2022/6/11
func (c *client) getCfg(cfgPath string) (*cfgFile, error) {
fileArr := strings.Split(cfgPath, ".")
if len(fileArr) < 2 {
// 获取不到类型
return nil, errors.New("文件格式必须是JSON或者YAML")
}
fileType := strings.ToLower(fileArr[len(fileArr)-1])
2022-06-11 19:05:54 +08:00
fileFlagArr := strings.Split(fileArr[0], string(filepath.Separator))
result := &cfgFile{
Path: cfgPath,
Type: "",
Flag: fileFlagArr[len(fileFlagArr)-1],
Config: Database{},
}
2022-06-11 18:25:00 +08:00
var (
err error
2022-06-11 19:05:54 +08:00
cfgInfo Database
2022-06-11 18:25:00 +08:00
)
switch fileType {
case FileTypeYaml:
fallthrough
case FileTypeYml:
result.Type = FileTypeYaml
if err = util.File.ReadYmlContent(cfgPath, &result.Config); nil != err {
return nil, fmt.Errorf("%s 配置文件解析失败, 原因 : %s", cfgPath, err.Error())
}
case FileTypeJson:
result.Type = FileTypeJson
if err = util.File.ReadJSONContent(cfgPath, &cfgInfo); nil != err {
return nil, fmt.Errorf("%s 配置文件解析失败, 原因 : %s", cfgPath, err.Error())
}
default:
// 不是JSON , 也不是YML, 跳过
return nil, nil
}
2022-06-11 19:05:54 +08:00
if len(result.Config.Master.Timezone) == 0 {
// 默认使用本地时区
result.Config.Master.Timezone = "Local"
} else {
result.Config.Slave.Timezone = result.Config.Master.Timezone
}
return result, nil
2022-06-11 18:25:00 +08:00
}
2022-06-05 19:49:45 +08:00
// GetDBClient 获取db client
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 19:32 2022/6/5
2022-06-11 18:00:47 +08:00
func (c *client) GetDBClient(dbFlag string) (*DBClient, error) {
2022-06-05 19:49:45 +08:00
c.lock.RLock()
defer c.lock.RUnlock()
var (
exist bool
dbClient *DBClient
)
if dbClient, exist = c.clientTable[dbFlag]; !exist {
return nil, fmt.Errorf("%s 标识的数据库实例不存在! ", dbFlag)
}
return dbClient, nil
}
// GetMasterClient 获取主库客户端
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 19:36 2022/6/5
func (c *client) GetMasterClient(ctx *gin.Context, dbFlag string) (*gorm.DB, error) {
var (
err error
dbClient *DBClient
)
2022-06-11 18:00:47 +08:00
if dbClient, err = c.GetDBClient(dbFlag); nil != err {
2022-06-05 19:49:45 +08:00
return nil, err
}
session := dbClient.master.Session(&gorm.Session{})
session.Logger = dbClient.getLogger(ctx, session, dbFlag+"-master")
return session, nil
}
// GetSlaveClient 获取从库客户端
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 19:37 2022/6/5
func (c *client) GetSlaveClient(ctx *gin.Context, dbFlag string) (*gorm.DB, error) {
var (
err error
dbClient *DBClient
)
2022-06-11 18:00:47 +08:00
if dbClient, err = c.GetDBClient(dbFlag); nil != err {
2022-06-05 19:49:45 +08:00
return nil, err
}
session := dbClient.slave.Session(&gorm.Session{})
session.Logger = dbClient.getLogger(ctx, session, dbFlag+"-slave")
return session, nil
}
// getGormClient 获取GORM client方法
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 11:24 2022/6/6
func (c *client) getGormClient() (*gorm.DB, error) {
return nil, nil
}
2022-06-11 19:05:54 +08:00
// GetDatabaseClient 获取数据库连接
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 18:41 2022/6/11
2022-07-15 00:38:20 +08:00
func (c *client) GetDatabaseClient(conf *Mysql, logInstance *zap.Logger) (*gorm.DB, error) {
2022-06-11 19:05:54 +08:00
var (
2022-07-15 00:38:20 +08:00
instance *gorm.DB
err error
2022-06-11 19:05:54 +08:00
)
if instance, err = gorm.Open(mysql.Open(c.buildConnectionDSN(conf)), &gorm.Config{}); nil != err {
return nil, err
}
2022-07-15 00:38:20 +08:00
instance.Logger = wrapper.NewGormLoggerWithInstance(nil, instance, logInstance, "", nil)
2022-06-11 19:05:54 +08:00
return instance, nil
}
// buildConnectionDSN 构建连接信息
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 18:42 2022/6/11
func (c *client) buildConnectionDSN(conf *Mysql) string {
return fmt.Sprintf(
"%s:%s@tcp(%s:%d)/%s?charset=%s&parseTime=True&loc=%s",
conf.Username,
conf.Password,
conf.Host,
conf.Port,
conf.Database,
conf.Charset,
conf.Timezone,
)
}
2022-05-15 11:27:28 +08:00
// DBClient 包装日志实例
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 3:09 PM 2021/12/24
type DBClient struct {
2022-06-05 16:25:05 +08:00
dbFlag string // 数据库标识
loggerInstance *zap.Logger // 日志实例
master *gorm.DB // 主库
slave *gorm.DB // 从库
extraFieldList []string // 提取的字段
2022-06-11 19:05:54 +08:00
cfg Mysql // 数据库配置
2022-06-05 16:25:05 +08:00
}
// SetFlag 设置数据库标识
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 16:18 2022/6/5
func (dc *DBClient) SetFlag(dbFlag string) {
dc.dbFlag = dbFlag
2022-05-15 11:27:28 +08:00
}
// GetMaster 获取主库连接
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 3:28 PM 2021/12/24
func (dc *DBClient) GetMaster(ctx *gin.Context) *gorm.DB {
session := dc.master.Session(&gorm.Session{})
session.Logger = dc.getLogger(ctx, session, "slave")
return session
}
// GetSlave 获取从库链接
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 3:29 PM 2021/12/24
func (dc *DBClient) GetSlave(ctx *gin.Context) *gorm.DB {
session := dc.slave.Session(&gorm.Session{})
session.Logger = dc.getLogger(ctx, session, "slave")
return session
}
// getLogger 获取日志实例
//
// Author : go_developer@163.com<白茶清欢>
//
// Date : 3:45 PM 2021/12/24
func (dc *DBClient) getLogger(ctx *gin.Context, dbClient *gorm.DB, node string) gormLogger.Interface {
2023-02-12 16:07:19 +08:00
return wrapper.NewGormLoggerWithInstance(ctx, dbClient, dc.loggerInstance, dc.dbFlag+"|"+node, dc.extraFieldList)
2022-05-15 11:27:28 +08:00
}