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