go项目中使用gorm集成多方数据库(MySQL、PostgreSQL、人大金仓、达梦、神州通用、南大通用)

在这里插入图片描述

项目背景:

需要在go项目中,使用gorm来连接访问不同的数据库,一共要支持适配6种,网上查阅了大量的资料,gorm对于MySQL、PostgreSQL本身就支持,但是对于我们使用的一些国产数据库(人大金仓、达梦、神州通用、南大通用) 相关的数据适配驱动并不存在,需要自己大量查阅资料,自己组装与适配,耗费了大量时间,最终终于搞出来了(当然了,如果使用zorm的话本身就适配各大国产数据库,但是我们选用的是gorm–使用人数更多,更完善的维护机制,所以要进行一些适配工作)

设计一个支持多种数据库(MySQL、PostgreSQL、人大金仓、达梦、神州通用、南大通用)的通用数据库连接仓库,需要同时满足以下需求:

  1. 多数据库支持:使用GORM的Dialector动态管理不同数据库的连接。
  2. 连接池配置:允许数据库连接池参数,如最大配置连接数、空闲连接数、连接超时时间等。
  3. 扩展性:针对人大金仓和大梦数据库,需实现兼容 GORM 的驱动。
  4. 统一管理与复用:通过统一接口管理多数据库连接实例。
  5. 可测试性:提供示例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.gopackage 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")
}

测试方法

  1. 在app.yaml中配置不同数据库的连接。
  2. 启动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
}

项目中的数据库管理目录 ==》 内部调用包中封装好的数据库包

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

卜锦元

白嫖是人类的终极快乐,我也是

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值