数据库应该可以支持多个库

看了下数据库配置这块,个人感觉是应该需要支持多个库的,目前我个人的改造方法如下,不知道合理不合理。

pkg/database/database.go 文件:

package database

import (
    "database/sql"

    "gorm.io/gorm"
)

type DBInfo struct {
    DB    *gorm.DB
    SQLDB *sql.DB
}

var DBCollections map[string]*DBInfo

// GetDB 获取对应 database 的 连接

func  DB(name ...string) *gorm.DB {
    if  len(name) >  0 {
        if  collect, ok  := DBCollections[name[0]]; ok {
            return collect.DB
        }
        return  nil
    }
    return DBCollections["default"].DB
}

config/database.go 文件:

package config

import (
    "gohub/passport/pkg/config"
)

func init() {
    config.Add("database", func() map[string]interface{} {
        return map[string]interface{}{

            // 默认数据库
            "connection": config.Env("DB_CONNECTION", "mysql"),

            "mysql": map[string]interface{}{

                // 默认数据库
                "default": map[string]interface{}{
                    // 数据库连接
                    "host":     config.Env("DB_HOST", "127.0.0.1"),
                    "port":     config.Env("DB_PORT", "3306"),
                    "database": config.Env("DB_DATABASE", ""),
                    "username": config.Env("DB_USERNAME", ""),
                    "password": config.Env("DB_PASSWORD", ""),
                    "charset":  "utf8mb4",

                    // 日志级别 1 Silent 2 Error 3 Warn 4 Info

                    "log_level": config.GetInt("DB_LOGGER_LEVEL", 4),

                    // 连接池配置
                    "max_idle_connections": config.Env("DB_MAX_IDLE_CONNECTIONS", 100),
                    "max_open_connections": config.Env("DB_MAX_OPEN_CONNECTIONS", 25),
                    "max_life_seconds":     config.Env("DB_MAX_LIFE_SECONDS", 5*60),
                },
            },
            "sqlite": map[string]interface{}{
                "default": map[string]interface{}{
                    "database": config.Env("DB_SQL_FILE", "database/database.db"),
                },
            },
        }
    })
}

bootstrap/database.go 文件

package bootstrap

import (
    "database/sql"
    "errors"
    "fmt"
    "time"

    "gorm.io/driver/mysql"
    "gorm.io/driver/sqlite"
    "gorm.io/gorm"
    "gorm.io/gorm/logger"
    "gohub/passport/pkg/config"
    "gohub/passport/pkg/database"
)

// SetupDB 初始化数据库和orm
func SetupDB() {
    var dbConfigs map[string]gorm.Dialector
    switch config.Get("database.connection") {
    case "mysql":
        connectInfo := config.GetStringMapString("database.mysql")
        for name := range connectInfo {
            dsn := fmt.Sprintf("%v:%v@tcp(%v:%v)/%v?charset=%v&parseTime=True&multiStatements=true&loc=Local",
                config.Get("database.mysql."+name+".username"),
                config.Get("database.mysql."+name+".password"),
                config.Get("database.mysql."+name+".host"),
                config.Get("database.mysql."+name+".port"),
                config.Get("database.mysql."+name+".database"),
                config.Get("database.mysql."+name+".charset"),
            )
            if dbConfigs == nil {
                dbConfigs = make(map[string]gorm.Dialector, len(connectInfo))
            }
            dbConfigs[name] = mysql.New(mysql.Config{
                DSN: dsn,
            })

        }
    case "sqlite":
        connectInfo := config.GetStringMapString("database.sqlite")
        for name := range connectInfo {

            database := config.Get("database.sqlite." + name + ".database")
            if dbConfigs == nil {
                dbConfigs = make(map[string]gorm.Dialector, len(connectInfo))
            }
            dbConfigs[name] = sqlite.Open(database)
        }
    default:
        panic(errors.New("database connection not supported"))
    }

    for k, v := range dbConfigs {
        if database.DBCollections == nil {
            database.DBCollections = make(map[string]*database.DBInfo, len(dbConfigs))
        }
        db, sqlDb, err := connect(v, logger.Default.LogMode(logger.LogLevel(config.GetInt("database.mysql."+k+".log_level"))))
        if err != nil {
            panic(err)
        }
        dbStruct := &database.DBInfo{
            DB:    db,
            SQLDB: sqlDb,
        }
        database.DBCollections[k] = dbStruct
        database.DBCollections[k].SQLDB.SetMaxIdleConns(config.GetInt("database.mysql." + k + ".max_idle_connections"))
        database.DBCollections[k].SQLDB.SetMaxOpenConns(config.GetInt("database.mysql." + k + ".max_open_connections"))
        database.DBCollections[k].SQLDB.SetConnMaxLifetime(time.Duration(config.GetInt("database.mysql."+k+".max_life_seconds")) * time.Second)
    }
}

// connect 连接数据库
func connect(dbConfig gorm.Dialector, _logger logger.Interface) (*gorm.DB, *sql.DB, error) {
    db, err := gorm.Open(
        dbConfig,
        &gorm.Config{
            Logger: _logger,
        },
    )
    if err != nil {
        return nil, nil, err
    }
    sqlDb, err := db.DB()
    if err != nil {
        return nil, nil, err
    }
    return db, sqlDb, nil
}

这边改造是基于项目有可能不单纯使用一个库的原则考虑的,因为我司目前项目就是差不多有三十多个库,可能会使用到其他库。

本帖已被设为精华帖!
本帖由系统于 2个月前 自动加精
讨论数量: 1

这种多数据库的连接,关于数据库的选择是如何优雅的处理呢?比如在 app/models/user.go 里面,有一个 func(userModel *User) Create() 方法。我目前想到的方法是,调用 user.Create() 方法的时候,传入 driver 参数。

app/models/user.go 中,修改 Create() 方法为:

func(userModel *User) Create(driver string) {
    database.DB(driver).Create(&userModel)
}

但是如果这么做的话,是不是意味着在 models 中所有操作 db 的方法,都需要传入 driver 参数呢?是否有优雅的方式来实现在 modes/xxx.go 中关于数据库句柄的选择呢?

1年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!