Golang Gorm框架初始化的優美解決方案


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()
	}
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM