当前位置 : 主页 > 编程语言 > 其它开发 >

Golang Gorm框架初始化的优美解决方案

来源:互联网 收集:自由互联 发布时间:2022-05-30
Gorm解析 gorm,orm框架 Config.yaml mysql: host: 127.0.0.1 #地址 port: "3306" #端口 config: charset=utf8mb4parseTime=Trueloc=Local #配置 db-name: gva #数据库名称 username: root #账号 password: root #密码 max-idle-conns: 0
Gorm解析

gorm,orm框架

Config.yaml
mysql:
  host: 127.0.0.1 #地址
  port: "3306" #端口
  config: charset=utf8mb4&parseTime=True&loc=Local #配置
  db-name: gva #数据库名称
  username: root #账号
  password: root #密码
  max-idle-conns: 0 #最大空闲连接数
  max-open-conns: 0 #最大连接数
  log-mode: "" #是否开启Gorm全局日志
  log-zap: false #是否打印日志到zap
配置文件
package config

import (
	"catering/pkg/e"
)

type Mysql struct {
	Host         string `json:"host" yaml:"host"`                   // 服务器地址
	Port         string `json:"port" yaml:"port"`                   // 端口
	Config       string `json:"config" yaml:"config"`               // 高级配置
	Dbname       string `json:"dbname" yaml:"db-name"`              // 数据库名
	Username     string `json:"username" yaml:"username"`           // 数据库用户名
	Password     string `json:"password" yaml:"password"`           // 数据库密码
	MaxIdleConns int    `json:"maxIdleConns" yaml:"max-idle-conns"` // 空闲中的最大连接数
	MaxOpenConns int    `json:"maxOpenConns" yaml:"max-open-conns"` // 打开到数据库的最大连接数
	MaxLifeTime  int    `json:"maxLifeTime" yaml:"max-life-time"`
	LogMode      string `json:"logMode" yaml:"log-mode"` // 是否开启Gorm全局日志
	LogZap       bool   `json:"logZap" yaml:"log-zap"`   // 是否通过zap写入日志文件
}

func (m *Mysql) Check() error {
	if m.Username == "" || m.Dbname == "" {
		return e.ErrMysqlConfigCheckFail
	}
	return nil
}

func (m *Mysql) Dsn() string {
	return m.Username + ":" + m.Password + "@tcp(" + m.Host + ":" + m.Port + ")/" + m.Dbname + "?" + m.Config
}

初始化
package initialize

import (
	"catering/global"
	"database/sql"
	"fmt"
	"log"
	"os"
	"time"

	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
)

func GormMysql() *gorm.DB {
	//获取配置文件的配置
	cfg := global.Config.Mysql
	//检查配置
	if err := cfg.Check(); err != nil {
		global.Log.Error(err.Error())
		return nil
	}
	mysqlConfig := mysql.Config{
		DSN:                       cfg.Dsn(), // DSN data source name
		DefaultStringSize:         255,       // string 类型字段的默认长度
		DisableDatetimePrecision:  true,      // 禁用 datetime 精度,MySQL 5.6 之前的数据库不支持
		DontSupportRenameIndex:    true,      // 重命名索引时采用删除并新建的方式,MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引
		DontSupportRenameColumn:   true,      // 用 `change` 重命名列,MySQL 8 之前的数据库和 MariaDB 不支持重命名列
		SkipInitializeWithVersion: false,     // 根据当前 MySQL 版本自动配置
	}
	//连接数据库
	db, err := gorm.Open(mysql.New(mysqlConfig), getGormConfig())
	if err != nil {
		return nil
	}
	sqlDB, _ := db.DB()
	if err := sqlDB.Ping(); err != nil {
		global.Log.Error(err.Error())
		return nil
	}
	// 设置默认值
	// SetMaxIdleConns 设置空闲连接池中连接的最大数量
	sqlDB.SetMaxIdleConns(10)
	// SetMaxOpenConns 设置打开数据库连接的最大数量。
	sqlDB.SetMaxOpenConns(100)
	// SetConnMaxLifetime 设置了连接可复用的最大时间。
	sqlDB.SetConnMaxLifetime(time.Hour)

	Options(sqlDB, WithMaxIdelConns(cfg.MaxIdleConns), WithMaxOpenConns(cfg.MaxOpenConns), WithMaxLifeTime(cfg.MaxLifeTime))
	return db
}

func getGormConfig() *gorm.Config {
	//禁用外键约束
	config := &gorm.Config{DisableForeignKeyConstraintWhenMigrating: true}

	//NewWriter 对log.New函数的再次封装,从而实现是否通过zap打印日志
	_default := logger.New(NewWriter(log.New(os.Stdout, "\r\n", log.LstdFlags)), logger.Config{
		SlowThreshold: 200 * time.Millisecond,
		LogLevel:      logger.Warn,
		Colorful:      true,
	})

	//设置logger的日志输出等级
	switch global.Config.Mysql.LogMode {
	case "silent", "Silent":
		config.Logger = _default.LogMode(logger.Silent)
	case "error", "Error":
		config.Logger = _default.LogMode(logger.Error)
	case "warn", "Warn":
		config.Logger = _default.LogMode(logger.Warn)
	case "info", "Info":
		config.Logger = _default.LogMode(logger.Info)
	default:
		config.Logger = _default.LogMode(logger.Info)
	}
	return config
}

type writer struct {
	logger.Writer
}

// NewWriter writer 构造函数
func NewWriter(w logger.Writer) *writer {
	return &writer{Writer: w}
}

// Printf 格式化打印日志
func (w *writer) Printf(message string, data ...interface{}) {
	var logZap bool
	switch global.Config.System.DbType {
	case "mysql":
		logZap = global.Config.Mysql.LogZap
	}
	//通过zap打印日志,或者其他
	if logZap {
		global.Log.Info(fmt.Sprintf(message+"\n", data...))
	} else {
		w.Writer.Printf(message, data...)
	}
}

//Option设计模式封装mysql的额外配置
type Option func(m *sql.DB)

func WithMaxIdelConns(idle int) Option {
	return func(m *sql.DB) {
		if idle == 0 {
			return
		}
		m.SetMaxIdleConns(idle)
	}
}

func WithMaxOpenConns(open int) Option {
	return func(m *sql.DB) {
		if open == 0 {
			return
		}
		m.SetMaxOpenConns(open)
	}
}

func WithMaxLifeTime(t int) Option {
	return func(m *sql.DB) {
		if t == 0 {
			return
		}
		m.SetConnMaxLifetime(time.Duration(t) * time.Second)
	}
}
func Options(m *sql.DB, opts ...Option) {
	for _, opt := range opts {
		opt(m)
	}
}

用法
package global

import (
	"github.com/go-redis/redis/v8"
	"go.uber.org/zap"
	"golang.org/x/sync/singleflight"

	"catering/config"

	"gorm.io/gorm"
)

var (
	DB                  *gorm.DB
)

package initialize

import (
	"catering/global"

	"gorm.io/gorm"
)

// Gorm 初始化数据库并产生数据库全局变量
// Author SliverHorn
func InitGorm() {
	var db *gorm.DB
	switch global.Config.System.DbType {
	case "mysql":
		db = GormMysql()
	default:
		db = GormMysql()
	}

	global.DB = db
}

package main

import (
	"catering/initialize"
    "catering/global"
)

func main() {
	initialize.InitGorm()
	if global.DB != nil {
		db, _ := global.DB.DB()
		defer db.Close()
	}
}
上一篇:String、StringBuilder和StringBuffer
下一篇:没有了
网友评论