项目背景:
需要在go项目中,使用gorm来连接访问不同的数据库,一共要支持适配6种,网上查阅了大量的资料,gorm对于MySQL、PostgreSQL本身就支持,但是对于我们使用的一些国产数据库(人大金仓、达梦、神州通用、南大通用) 相关的数据适配驱动并不存在,需要自己大量查阅资料,自己组装与适配,耗费了大量时间,最终终于搞出来了(当然了,如果使用zorm的话本身就适配各大国产数据库,但是我们选用的是gorm–使用人数更多,更完善的维护机制,所以要进行一些适配工作)
设计一个支持多种数据库(MySQL、PostgreSQL、人大金仓、达梦、神州通用、南大通用)的通用数据库连接仓库,需要同时满足以下需求:
- 多数据库支持:使用GORM的Dialector动态管理不同数据库的连接。
- 连接池配置:允许数据库连接池参数,如最大配置连接数、空闲连接数、连接超时时间等。
- 扩展性:针对人大金仓和大梦数据库,需实现兼容 GORM 的驱动。
- 统一管理与复用:通过统一接口管理多数据库连接实例。
- 可测试性:提供示例main.go演示如何初始化、连接和测试功能。
内容结构
project/
├── main.go # 主程序入口
├── config/
│ └── config.go # 配置加载模块
├── database/
│ ├── db.go # 数据库连接管理
├── manager.go # 数据库连接管理
│ ├── drivers/ # 自定义驱动
│ │ ├── kingbase.go # 人大金仓驱动
│ │ └── dm.go # 大梦驱动
│ ├── models/ # 数据模型
│ │ └── user.go # 示例模型
└── handlers/
└── user_handler.go # 示例业务逻辑
代码实现
步骤 1:配置模块
配置文件加载模块config/config.go:
package config
import (
"github.com/spf13/viper"
"log"
)
type DatabaseConfig struct {
Driver string `mapstructure:"driver"`
DSN string `mapstructure:"dsn"`
MaxIdleConns int `mapstructure:"max_idle_conns"`
MaxOpenConns int `mapstructure:"max_open_conns"`
ConnMaxLifetime int `mapstructure:"conn_max_lifetime"` // 单位:秒
}
type Config struct {
Databases []DatabaseConfig `mapstructure:"databases"`
}
// LoadConfig 加载配置
func LoadConfig(path string) (Config, error) {
viper.AddConfigPath(path)
viper.SetConfigName("app")
viper.SetConfigType("yaml")
viper.AutomaticEnv()
if err := viper.ReadInConfig(); err != nil {
return Config{}, err
}
var config Config
if err := viper.Unmarshal(&config); err != nil {
return Config{}, err
}
log.Println("Config loaded successfully")
return config, nil
}
配置文件app.yaml示例:
databases:
- driver: "mysql"
dsn: "root:admin123456@tcp(localhost:3306)/ceshi?charset=utf8mb4&parseTime=True&loc=Local"
dsn: "user:password@tcp(localhost:3306)/testdb?charset=utf8mb4&parseTime=True&loc=Local"
max_idle_conns: 10
max_open_conns: 100
conn_max_lifetime: 3600
- driver: "postgres.bak"
dsn: "host=localhost user=postgres password=secret dbname=testdb sslmode=disable"
max_idle_conns: 10
max_open_conns: 100
conn_max_lifetime: 3600
- driver: "kingbase.bak"
dsn: "user=kingbase password=kingbase dbname=testdb host=localhost port=54321 sslmode=disable"
max_idle_conns: 5
max_open_conns: 50
conn_max_lifetime: 3600
- driver: "dm.bak"
dsn: "dm://SYSDBA:SYSDBA@localhost:5236"
max_idle_conns: 5
max_open_conns: 50
conn_max_lifetime: 3600
步骤 2:数据库连接管理
创建database/db.go管理多数据库连接:
package database
import (
"dbConnect-go-demo/database/drivers"
"errors"
"log"
"sync"
"time"
"gorm.io/driver/mysql"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
var connections = make(map[string]*gorm.DB)
var mu sync.Mutex
// InitDB 初始化数据库连接
func InitDB(driver, dsn string, maxIdle, maxOpen, maxLifetime int) (*gorm.DB, error) {
// 数据库连接逻辑同之前实现
db, err := initializeConnection(driver, dsn, maxIdle, maxOpen, maxLifetime)
if err != nil {
return nil, err
}
// 添加到全局管理器
GetManager().AddConnection(driver, db)
return db, nil
}
// initializeConnection 封装具体的数据库连接逻辑
func initializeConnection(driver, dsn string, maxIdle, maxOpen, maxLifetime int) (*gorm.DB, error) {
mu.Lock()
defer mu.Unlock()
if db, exists := connections[driver]; exists {
return db, nil
}
var dialector gorm.Dialector
switch driver {
case "mysql":
dialector = mysql.Open(dsn)
case "postgres":
dialector = postgres.Open(dsn)
case "kingbase":
dialector = drivers.NewKingbaseDialector(dsn)
case "dm":
dialector = drivers.NewDmDialector(dsn)
default:
return nil, errors.New("database connection not found")
}
db, err := gorm.Open(dialector, &gorm.Config{})
if err != nil {
return nil, err
}
sqlDB, err := db.DB()
if err != nil {
return nil, err
}
sqlDB.SetMaxIdleConns(maxIdle)
sqlDB.SetMaxOpenConns(maxOpen)
sqlDB.SetConnMaxLifetime(time.Duration(maxLifetime) * time.Second)
connections[driver] = db
log.Printf("Database connected: %s", driver)
return db, nil
}
// GetDB 获取数据库实例
func GetDB(driver string) (*gorm.DB, bool) {
db, exists := connections[driver]
return db, exists
}
创建database/manager.go管理多数据库连接:
package database
import (
"errors"
"log"
"sync"
"gorm.io/gorm"
)
// DBManager 管理所有数据库连接
type DBManager struct {
mu sync.RWMutex
connections map[string]*gorm.DB
}
// 全局实例
var manager *DBManager
var once sync.Once
// GetManager 获取全局数据库管理器实例
func GetManager() *DBManager {
once.Do(func() {
manager = &DBManager{
connections: make(map[string]*gorm.DB),
}
})
return manager
}
// AddConnection 添加新的数据库连接
func (m *DBManager) AddConnection(name string, db *gorm.DB) {
m.mu.Lock()
defer m.mu.Unlock()
m.connections[name] = db
log.Printf("Database connection [%s] added successfully", name)
}
// GetConnection 获取指定名称的数据库连接
func (m *DBManager) GetConnection(name string) (*gorm.DB, error) {
m.mu.RLock()
defer m.mu.RUnlock()
db, exists := m.connections[name]
if !exists {
return nil, errors.New("database connection not found")
}
return db, nil
}
// CloseConnections 关闭所有数据库连接
func (m *DBManager) CloseConnections() error {
m.mu.Lock()
defer m.mu.Unlock()
for name, db := range m.connections {
sqlDB, err := db.DB()
if err != nil {
log.Printf("Error closing connection [%s]: %v", name, err)
continue
}
if err := sqlDB.Close(); err != nil {
log.Printf("Error closing connection [%s]: %v", name, err)
} else {
log.Printf("Database connection [%s] closed successfully", name)
}
}
m.connections = make(map[string]*gorm.DB)
return nil
}
步骤 3:自定义数据库驱动
人大金仓drivers/kingbase.go
package drivers
import (
"gorm.io/driver/postgres" // 金仓与 PostgreSQL 协议兼容
"gorm.io/gorm"
)
// NewKingbaseDialector 金仓驱动
func NewKingbaseDialector(dsn string) gorm.Dialector {
return postgres.Open(dsn)
}
大梦drivers/dm.go
package drivers
import (
"database/sql"
"fmt"
"gorm.io/gorm"
)
type DmDialector struct {
DSN string
}
//func NewDmDialector(dsn string) gorm.Dialector {
// return DmDialector{DSN: dsn}
//}
// Open 方法,创建 SQL 连接
func (d DmDialector) Open(dsn string) (*sql.DB, error) {
return sql.Open("dm", d.DSN)
}
// Initialize 初始化 GORM 的配置
func (d DmDialector) Initialize(db *gorm.DB) error {
callback := db.Callback()
callback.Create().Register("dm:insert", d.insertCallback)
callback.Update().Register("dm:update", d.updateCallback)
callback.Delete().Register("dm:delete", d.deleteCallback)
return nil
}
// 插入操作的回调
func (d DmDialector) insertCallback(tx *gorm.DB) {
fmt.Println("DM Insert Callback Triggered")
}
// 更新操作的回调
func (d DmDialector) updateCallback(tx *gorm.DB) {
fmt.Println("DM Update Callback Triggered")
}
// 删除操作的回调
func (d DmDialector) deleteCallback(tx *gorm.DB) {
fmt.Println("DM Delete Callback Triggered")
}
// 字段映射(可选)
//func (d DmDialector) DefaultSchema(schema.Table) string {
// return "public"
//}
步骤4:数据模型 --测试
创建用户模型database/models/user.go:
package models
type User struct {
ID uint `gorm:"primaryKey"`
Name string `gorm:"size:255"`
Email string `gorm:"unique"`
Password string `gorm:"size:255"`
}
创建handlers/user_handler.go,实现用户表的基本CRUD操作:
package handlers
import (
"dbConnect-go-demo/database/models"
"gorm.io/gorm"
)
// CreateUser 创建用户
func CreateUser(db *gorm.DB, name, email, password string) error {
user := models.User{Name: name, Email: email, Password: password}
return db.Create(&user).Error
}
// GetUser 查询用户
func GetUser(db *gorm.DB, id uint) (models.User, error) {
var user models.User
err := db.First(&user, id).Error
return user, err
}
// UpdateUser 更新用户信息
func UpdateUser(db *gorm.DB, id uint, name, email string) error {
var user models.User
if err := db.First(&user, id).Error; err != nil {
return err
}
user.Name = name
user.Email = email
return db.Save(&user).Error
}
// DeleteUser 删除用户
func DeleteUser(db *gorm.DB, id uint) error {
return db.Delete(&models.User{}, id).Error
}
步骤 5:主程序
main.go:
package main
import (
"dbConnect-go-demo/config"
"dbConnect-go-demo/database"
"dbConnect-go-demo/handlers"
"fmt"
"log"
)
func main() {
// 加载配置
cfg, err := config.LoadConfig(".")
if err != nil {
log.Fatalf("Failed to load config: %v", err)
}
// 初始化数据库连接
for _, dbConfig := range cfg.Databases {
_, err := database.InitDB(dbConfig.Driver, dbConfig.DSN, dbConfig.MaxIdleConns, dbConfig.MaxOpenConns, dbConfig.ConnMaxLifetime)
if err != nil {
log.Fatalf("Failed to connect to database %s: %v", dbConfig.Driver, err)
}
}
// 使用全局管理器获取数据库实例
manager := database.GetManager()
db, err := manager.GetConnection("mysql")
if err != nil {
log.Fatalf("Failed to get DM database connection: %v", err)
}
// 演示增删改查操作
fmt.Println("=== User CRUD Demo ===")
err = handlers.CreateUser(db, "Alice", "alice@example.com", "password123")
if err != nil {
log.Fatalf("Failed to create user: %v", err)
}
fmt.Println("User created successfully")
user, err := handlers.GetUser(db, 1)
if err != nil {
log.Fatalf("Failed to get user: %v", err)
}
fmt.Printf("User fetched: %+v\n", user)
// 关闭所有数据库连接
err = manager.CloseConnections()
if err != nil {
log.Fatalf("Failed to close database connections: %v", err)
}
fmt.Println("All database connections closed successfully")
}
测试方法
- 在app.yaml中配置不同数据库的连接。
- 启动main.go,验证各数据库是否成功连接并迁移模型。
总结
该方案实现了一个多数据库连接层,支持连接池配置、模型管理和扩展性。人大金仓和大梦数据库自定义通过Dialector实现对接,可根据实际需求进一步调整通用其细节实现。
后期补充:
对于封装的文件进行了更细致的补充,已经应用到生产环境中去了,主要增加了神州通用(难受的很,跟对方的技术沟通无数次。。),南大通用
db.go 重写==这个是封装包中的文件
package dao
import (
"context"
"errors"
"fmt"
"gitee.com/vrv_media/go-micro-framework/pkg/dao/drivers"
"github.com/go-redis/redis/v8"
"gorm.io/gorm/logger"
"io"
"log"
"sync"
"time"
"gorm.io/gorm"
)
var mu sync.Mutex
// InitRedisDB 初始化 Redis 客户端
func InitRedisDB(host string, port int) (*redis.Client, error) {
// 全局 Redis 连接存在,则直接返回
if RedisDb != nil {
return RedisDb, nil
}
// 创建 Redis 客户端
Addr := fmt.Sprintf("%s:%d", host, port)
client := redis.NewClient(&redis.Options{
Addr: Addr, // Redis 地址
Password: host, // 密码
DB: port, // 数据库编号
})
// 测试连接
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
_, err := client.Ping(ctx).Result()
if err != nil {
log.Fatalf("failed to connect to redis: %v", err)
}
log.Printf("db-Connected to Redis:success:%s\n", Addr)
RedisDb = client // 设置全局 Redis 连接 todo 这两种方式都可以
if err != nil {
return nil, err
}
return client, nil
}
// InitGormDB 封装具体的数据库连接逻辑
func InitGormDB(driver, host, userName, password, database string, port int, maxIdle, maxOpen, maxLifetime int) (*gorm.DB, error) {
mu.Lock()
defer mu.Unlock()
if GormDb != nil {
return GormDb, nil
}
var dialector gorm.Dialector
switch driver {
case "mysql": // mysql 数据库
dialector = drivers.NewMysqlDialector(host, userName, password, database, port) //mysql数据库
case "postgres": // postgres 数据库
dialector = drivers.NewPostgresDialector(host, userName, password, database, port) //postgres数据库
case "kingbase": // kingbase 数据库-人大金仓
dialector = drivers.NewKingbaseDialector(host, userName, password, database, port) //人大金仓数据库
case "dameng":
dialector = drivers.NewDmDialector(host, userName, password, database, port) //达梦数据库
case "gbase":
dialector = drivers.NewGBase8sDialector(host, userName, password, database, port) //南大通用数据库
case "gbase8a":
dialector = drivers.NewGBase8aDialector(host, userName, password, database, port) //南大通用数据库
case "shentong":
dialector = drivers.NewShentongDialector(host, userName, password, database, port) //神舟通用数据库
default:
return nil, errors.New("db-gorm Database connection not found")
}
// 日志输出到文件 todo
db, err := gorm.Open(dialector, &gorm.Config{})
if err != nil {
return nil, err
}
// 自动迁移表结构
//go func() {
// err := autoMigrate(db)
// if err != nil {
// log.Printf("auto migrate failed: %v", err)
// }
//}()
// 设置连接池参数
sqlDB, err := db.DB()
if err != nil {
return nil, err
}
sqlDB.SetMaxIdleConns(maxIdle) //设置最大空闲连接数
sqlDB.SetMaxOpenConns(maxOpen) //设置可打开的最大连接数为 100 个
sqlDB.SetConnMaxLifetime(time.Duration(maxLifetime) * time.Second) //设置一个连接空闲后在多长时间内可复用
log.Printf("db-gorm Database connected success: %s", driver)
// 添加到全局管理器
GormDb = db // 设置全局数据库连接
if err != nil {
return nil, err
}
return db, nil
}
// ConcreteObserver 具体的观察者
type ConcreteObserver struct {
name string
}
func (o *ConcreteObserver) Update(fileObj io.Writer) {
mu.Lock()
defer mu.Unlock()
newLogger := logger.New(
log.New(fileObj, "\n", log.LstdFlags), // 日志输出到文件
logger.Config{
LogLevel: logger.Info,
Colorful: true, // 开启彩色输出
},
)
GormDb.Config.Logger = newLogger
}
func byteString(p []byte) string {
for i := 0; i < len(p); i++ {
if p[i] == 0 {
return string(p[0:i])
}
}
return string(p)
}
func substr(str string, start int, end int) string {
rs := []rune(str)
length := len(rs)
if start < 0 || start > length {
return ""
}
if end < 0 || end > length {
return ""
}
if start >= end {
return ""
}
return string(rs[start:end])
}
神通驱动追加:
package drivers
import (
"fmt"
`gitee.com/vrv_media/go-micro-framework/pkg/dao/oscar`
"gorm.io/gorm"
)
// NewShentongDialector 创建mysql数据库驱动
func NewShentongDialector(host, userName, password, database string, port int) gorm.Dialector {
dsn := BuildShentongDsn(host, userName, password, database, port)
fmt.Println("神通数据库连接信息dsn:", dsn)
return oscar.Open(dsn)
}
func BuildShentongDsn(host, userName, password, database string, port int) string {
//return "sysdba/szoscar55@158.100.3.56:20003/osrdb"
return fmt.Sprintf("%s/%s@%s:%d/%s", userName, password, host, port, database)
//return fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local", userName, password, host, port, database)
}
达梦驱动
package drivers
import (
//`MediaSortingServer/MeetGo`
"fmt"
"github.com/godoes/gorm-dameng"
"gorm.io/gorm"
)
// NewDmDialector 达梦数据库驱动
func NewDmDialector(host, userName, password, database string, port int) gorm.Dialector {
//options := map[string]string{
// "schema": "SYSDBA",
// "appName": "GORM 连接达梦数据库示例",
// "connectTimeout": "30000",
//}
// dm://user:password@host:port?schema=SYSDBA[&...]
//dsn = dameng.BuildUrl("SYSDBA", "admin123456", "127.0.0.1", 5236, options)
dsn := BuildDmDsn(host, userName, password, database, port)
fmt.Println("达梦数据库连接信息dsn:", dsn)
//MeetGo.Log.Info("db-gorm-database-达梦数据库连接信息dsn:%s", dsn)
return dameng.Open(dsn)
}
func BuildDmDsn(host, userName, password, database string, port int) string {
return fmt.Sprintf("dm://%s:%s@%s:%d?schema=%s", userName, password, host, port, database)
}
//// VARCHAR 类型大小为字符长度
////db, err := gorm.Open(dameng.New(dameng.Config{DSN: dsn, VarcharSizeIsCharLength: true}))
//// VARCHAR 类型大小为字节长度(默认)
//db, err := gorm.Open(dameng.Open(dsn), &gorm.Config{})
//if err != nil {
// // panic error or log error info
//}
//
//// do somethings
//var versionInfo []map[string]interface{}
//db.Table("SYS.V$VERSION").Find(&versionInfo)
//if err := db.Error; err == nil {
// versionBytes, _ := json.MarshalIndent(versionInfo, "", " ")
// fmt.Printf("达梦数据库版本信息:\n%s\n", versionBytes)
//}
/****************** 控制台输出内容 *****************
达梦数据库版本信息:
[
{
"BANNER": "DM Database Server 64 V8"
},
{
"BANNER": "DB Version: 0x7000c"
},
{
"BANNER": "03134284094-20230927-******-*****"
}
]
*************************************************/
人大金仓驱动
package drivers
import (
//`MediaSortingServer/MeetGo`
"fmt"
"gorm.io/driver/postgres" // 金仓与 PostgreSQL 协议兼容
"gorm.io/gorm"
)
// NewKingbaseDialector 人大金仓数据库驱动
func NewKingbaseDialector(host, userName, password, database string, port int) gorm.Dialector {
dsn := BuildKingbaseDsn(host, userName, password, database, port)
fmt.Println("人大金仓数据库连接信息dsn:", dsn)
//MeetGo.Log.Info("db-gorm-database-人大金仓数据库连接信息dsn:%s", dsn)
return postgres.Open(dsn)
}
func BuildKingbaseDsn(host, userName, password, database string, port int) string {
return fmt.Sprintf("user=%s password=%s dbname=%s host=%s port=%d sslmode=disable", userName, password, database, host, port)
}
南大通用驱动
package drivers
import (
//`MediaSortingServer/MeetGo`
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
// NewGBase8aDialector 创建gbase数据库驱动
func NewGBase8aDialector(host, userName, password, database string, port int) gorm.Dialector {
// GBase 8a 的 DSN (数据源名称)
// 格式: "user:password@tcp(host:port)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
//dsn := "your_user:your_password@tcp(your_host:your_port)/your_dbname?charset=utf8mb4&parseTime=True&loc=Local"
dsn := BuildGBase8aDsn(host, userName, password, database, port)
fmt.Println("gbase8a数据库连接信息dsn:", dsn)
//MeetGo.Log.Info("db-gorm-database-gbase8a数据库连接信息dsn:%s", dsn)
return mysql.Open(dsn)
}
func BuildGBase8aDsn(host, userName, password, database string, port int) string {
return fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local", userName, password, host, port, database)
}
生产项目中使用,封装为包来访问
mysql数据驱动
package drivers
import (
//`MediaSortingServer/MeetGo`
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
// NewMysqlDialector 创建mysql数据库驱动
func NewMysqlDialector(host, userName, password, database string, port int) gorm.Dialector {
dsn := BuildMysqlDsn(host, userName, password, database, port)
fmt.Println("mysql数据库连接信息dsn:", dsn)
//MeetGo.Log.Info("db-gorm-database-mysql数据库连接信息dsn:%s", dsn)
return mysql.Open(dsn)
}
func BuildMysqlDsn(host, userName, password, database string, port int) string {
return fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local", userName, password, host, port, database)
}
postgresql驱动
package drivers
import (
//`MediaSortingServer/MeetGo`
"fmt"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
// NewPostgresDialector psostgres数据库驱动
func NewPostgresDialector(host, userName, password, database string, port int) gorm.Dialector {
dsn := BuildPostgresDsn(host, userName, password, database, port)
fmt.Println("postgres数据库连接信息dsn:", dsn)
//MeetGo.Log.Info("db-gorm-database-postgres数据库连接信息dsn:%s", dsn)
return postgres.Open(dsn)
}
func BuildPostgresDsn(host, userName, password, database string, port int) string {
return fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=disable", host, port, userName, password, database)
}
global文件内容
package dao
import (
"github.com/go-redis/redis/v8"
"gorm.io/gorm"
)
var (
GormDb *gorm.DB
RedisDb *redis.Client
)
关于oscar 可以找 神州通用数据库的技术支持获取完整的包,go-aci也是,都在里面包含着(不涉及神通数据库适配就不用管,神通的适配最是麻烦。。。)
db.go ==这个是项目中的调用控制的文件(项目的db.go调用封装包中的db.go)
package db
import (
"MediaSortingServer/MeetGo"
"gitee.com/vrv_media/go-micro-framework/pkg/dao"
zaplogger "gitee.com/vrv_media/go-micro-framework/pkg/logger"
"gitee.com/vrv_media/go-micro-framework/vrv/crypt"
"gorm.io/gorm/logger"
"io"
"log"
"sync"
)
var mu sync.Mutex
// InitDB 初始化数据库连接
func InitDB(cfg *MeetGo.MyConfig) error {
// 初始化数据库连接 gorm
//fmt.Println("gorm-database-config-init", cfg.Database)
zaplogger.InfoF("db-gorm-database-config-init ")
// 解密数据库用户名和密码 start
strKey := cfg.Dataserver.Aid + cfg.Dataserver.Elogo // 密钥 == 给空值
zaplogger.InfoF("strKey--%s", strKey)
zaplogger.InfoF("盐值:%s", strKey)
//解密数据库用户名和密码
strUsername := crypt.StrDecrypt(cfg.Database.User, strKey)
strPassword := crypt.StrDecrypt(cfg.Database.Password, strKey)
zaplogger.InfoF("db-gorm-database-数据库用户名原始字符:%s ,最终用户账号(长度):%d \n", cfg.Database.User, len(strUsername))
zaplogger.InfoF("db-gorm-database-数据库密码原始字符:%s ,最终用户密码(长度):%d \n", cfg.Database.Password, len(strPassword))
zaplogger.InfoF("go-micro-framework-db-int start")
// 初始化数据库连接gorm
_, err := dao.InitGormDB(cfg.Database.DbType, cfg.Database.Host, strUsername, strPassword, cfg.Database.DBName, cfg.Database.Port, 10, 100, 3600)
if err != nil {
zaplogger.ErrorF("db-gorm-database-config-init failed, error:%s", err.Error())
return err
}
// 配置 GORM 日志记录器
if cfg.LoggerConfig.GormLogSwitch {
gormLog() // 配置 GORM 日志记录器
}
// 初始化 Redis 连接
zaplogger.InfoF("db-redis-config-init: %v", cfg.Redis)
if cfg.Redis.Host != "" {
_, err := dao.InitRedisDB(cfg.Redis.Host, cfg.Redis.Port)
if err != nil { // 初始化 Redis 连接失败
log.Fatalf("Failed to connect to Redis: %v", err)
}
}
zaplogger.InfoF("go-micro-framework-db-int end")
// 初始化其他连接(es、kafka、mongodb)等 todo
return nil
}
func gormLog() {
gormLogger := NewGormLogger()
dao.GormDb.Config.Logger = gormLogger
}
// ConcreteObserver 具体的观察者
type ConcreteObserver struct {
name string
}
func (o *ConcreteObserver) Update(fileObj io.Writer) {
mu.Lock()
defer mu.Unlock()
newLogger := logger.New(
log.New(fileObj, "\n", log.LstdFlags), // 日志输出到文件
logger.Config{
LogLevel: logger.Info,
Colorful: true, // 开启彩色输出
},
)
dao.GormDb.Config.Logger = newLogger
}