Во многих платформах используются модели ORM для представления отношений сопоставления между классами моделей и таблицами базы данных. В этой статье в качестве библиотеки ORM будет использоваться gorm[1], которая следует шаблону ActiveRecord (однозначное соответствие между моделями и таблицами базы данных). предоставляет мощные функции, такие как ассоциация модели, предварительная загрузка ассоциации, миграция базы данных и т. д. Для получения дополнительной информации см. официальную документацию [2].
go get -u gorm.io/gorm
# GORM Официальная поддержка sqlite、mysql、postgres、sqlserver
go get -u gorm.io/driver/mysql
Новый config/database.go
Файл из Определить элементы конфигурации
package config
type Database struct {
Driver string `mapstructure:"driver" json:"driver" yaml:"driver"`
Host string `mapstructure:"host" json:"host" yaml:"host"`
Port int `mapstructure:"port" json:"port" yaml:"port"`
Database string `mapstructure:"database" json:"database" yaml:"database"`
UserName string `mapstructure:"username" json:"username" yaml:"username"`
Password string `mapstructure:"password" json:"password" yaml:"password"`
Charset string `mapstructure:"charset" json:"charset" yaml:"charset"`
MaxIdleConns int `mapstructure:"max_idle_conns" json:"max_idle_conns" yaml:"max_idle_conns"`
MaxOpenConns int `mapstructure:"max_open_conns" json:"max_open_conns" yaml:"max_open_conns"`
LogMode string `mapstructure:"log_mode" json:"log_mode" yaml:"log_mode"`
EnableFileLogWriter bool `mapstructure:"enable_file_log_writer" json:"enable_file_log_writer" yaml:"enable_file_log_writer"`
LogFilename string `mapstructure:"log_filename" json:"log_filename" yaml:"log_filename"`
}
config/config.go
добавить в Database
свойства члена
package config
type Configuration struct {
App App `mapstructure:"app" json:"app" yaml:"app"`
Log Log `mapstructure:"log" json:"log" yaml:"log"`
Database Database `mapstructure:"database" json:"database" yaml:"database"`
}
config.yaml
Добавьте соответствующие элементы конфигурации
database:
driver: mysql # база данныхводить машину host: 127.0.0.1 # доменное имя
port: 3306 # номер порта
database: go-test # база данныхимя username: root # имя пользователя
password: root # пароль
charset: utf8mb4 # формат кодирования
max_idle_conns: 10 # Максимальное количество соединений в пуле свободных соединений
max_open_conns: 100 # Открытая база Максимальное количество подключений данных
log_mode: info # Уровень журнала
enable_file_log_writer: true # Включить ли файлы журналов
log_filename: sql.log # Имя файла журнала
gorm
Есть значение по умолчанию logger[3] ,Поскольку содержимое журнала выводится на консоль,Нам нужен писатель,будет по умолчаниюlogger.Writer
Реализация интерфейса переключена на собственный модуль записи, который был представлен в предыдущей статье. lumberjack
, буду продолжать его использовать.
Новый bootstrap/db.go
документ, напиши getGormLogWriter
функция:
package bootstrap
import (
"gopkg.in/natefinch/lumberjack.v2"
"gorm.io/gorm/logger"
"io"
"jassue-gin/global"
"log"
"os"
)
// Настроить gorm Writer
func getGormLogWriter() logger.Writer {
var writer io.Writer
// Включить ли файлы журналов
if global.App.Config.Database.EnableFileLogWriter {
// Настроить Writer
writer = &lumberjack.Logger{
Filename: global.App.Config.Log.RootDir + "/" + global.App.Config.Database.LogFilename,
MaxSize: global.App.Config.Log.MaxSize,
MaxBackups: global.App.Config.Log.MaxBackups,
MaxAge: global.App.Config.Log.MaxAge,
Compress: global.App.Config.Log.Compress,
}
} else {
// по умолчанию Writer
writer = os.Stdout
}
return log.New(writer, "\r\n", log.LstdFlags)
}
Далее пишите getGormLogger
функция, переключиться по умолчанию Logger
использовал Writer
func getGormLogger() logger.Interface {
var logMode logger.LogLevel
switch global.App.Config.Database.LogMode {
case "silent":
logMode = logger.Silent
case "error":
logMode = logger.Error
case "warn":
logMode = logger.Warn
case "info":
logMode = logger.Info
default:
logMode = logger.Info
}
return logger.New(getGormLogWriter(), logger.Config{
SlowThreshold: 200 * time.Millisecond, // медленный SQL порог
LogLevel: logMode, // Уровень журнала
IgnoreRecordNotFoundError: false, // Игнорировать ошибки ErrRecordNotFound (запись не найдена)
Colorful: !global.App.Config.Database.EnableFileLogWriter, // Отключить цветную печать
})
}
На этом этапе настройте Logger Это уже реализовано, вот простая замена logger.Writer
реализации каждый может создавать другие индивидуальные конфигурации в соответствии со своими потребностями.
существовать bootstrap/db.go
файл, написать InitializeDB
Инициализировать базу данныхфункция,чтобы облегчитьсуществовать main.go
позвонить
package bootstrap
import (
"gopkg.in/natefinch/lumberjack.v2"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"io"
"jassue-gin/global"
"log"
"os"
"strconv"
"time"
)
func InitializeDB() *gorm.DB {
// Инициализируйте в соответствии с конфигурацией драйвера
switch global.App.Config.Database.Driver {
case "mysql":
return initMySqlGorm()
default:
return initMySqlGorm()
}
}
// инициализация mysql gorm.DB
func initMySqlGorm() *gorm.DB {
dbConfig := global.App.Config.Database
if dbConfig.Database == "" {
return nil
}
dsn := dbConfig.UserName + ":" + dbConfig.Password + "@tcp(" + dbConfig.Host + ":" + strconv.Itoa(dbConfig.Port) + ")/" +
dbConfig.Database + "?charset=" + dbConfig.Charset +"&parseTime=True&loc=Local"
mysqlConfig := mysql.Config{
DSN: dsn, // DSN data source name
DefaultStringSize: 191, // string по типа поля умолчаниюдлина
DisableDatetimePrecision: true, // Запрещать datetime Точность, MySQL 5.6 Предыдущая база данных Не поддерживается DontSupportRenameIndex: true, // При переименовании индекса удалите и объедините его, MySQL 5.7 Предыдущая база данныхи MariaDB Переименование индексов не поддерживается.
DontSupportRenameColumn: true, // использовать `change` Переименование столбцов, MySQL 8 Предыдущая база данныхи MariaDB Переименование столбцов не поддерживается.
SkipInitializeWithVersion: false, // Автоматическая настройка в зависимости от версии
}
if db, err := gorm.Open(mysql.New(mysqlConfig), &gorm.Config{
DisableForeignKeyConstraintWhenMigrating: true, // Запрещать автоматическое создание ограничений внешнего ключа
Logger: getGormLogger(), // делатьиспользовать Настроить Logger
}); err != nil {
global.App.Log.Error("mysql connect failed, err:", zap.Any("err", err))
return nil
} else {
sqlDB, _ := db.DB()
sqlDB.SetMaxIdleConns(dbConfig.MaxIdleConns)
sqlDB.SetMaxOpenConns(dbConfig.MaxOpenConns)
return db
}
}
func getGormLogger() logger.Interface {
var logMode logger.LogLevel
switch global.App.Config.Database.LogMode {
case "silent":
logMode = logger.Silent
case "error":
logMode = logger.Error
case "warn":
logMode = logger.Warn
case "info":
logMode = logger.Info
default:
logMode = logger.Info
}
return logger.New(getGormLogWriter(), logger.Config{
SlowThreshold: 200 * time.Millisecond, // медленный SQL порог
LogLevel: logMode, // Уровень журнала
IgnoreRecordNotFoundError: false, // Игнорировать ошибки ErrRecordNotFound (запись не найдена)
Colorful: !global.App.Config.Database.EnableFileLogWriter, // Отключить цветную печать
})
}
// Настроить gorm Writer
func getGormLogWriter() logger.Writer {
var writer io.Writer
// Включить ли файлы журналов
if global.App.Config.Database.EnableFileLogWriter {
// Настроить Writer
writer = &lumberjack.Logger{
Filename: global.App.Config.Log.RootDir + "/" + global.App.Config.Database.LogFilename,
MaxSize: global.App.Config.Log.MaxSize,
MaxBackups: global.App.Config.Log.MaxBackups,
MaxAge: global.App.Config.Log.MaxAge,
Compress: global.App.Config.Log.Compress,
}
} else {
// по умолчанию Writer
writer = os.Stdout
}
return log.New(writer, "\r\n", log.LstdFlags)
}
Новый app/models/common.go
Файл, определяющий общедоступные поля модели.
package models
import (
"gorm.io/gorm"
"time"
)
// Первичный ключ идентификатора с автоинкрементом
type ID struct {
ID uint `json:"id" gorm:"primaryKey"`
}
// создать, обновить время
type Timestamps struct {
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
// мягкое удаление
type SoftDeletes struct {
DeletedAt gorm.DeletedAt `json:"deleted_at" gorm:"index"`
}
Новый app/models/user.go
файл, определение User
Модель
package models
type User struct {
ID
Name string `json:"name" gorm:"not null;comment:имя пользователясказать"`
Mobile string `json:"mobile" gorm:"not null;index;comment:использовать номер мобильного телефона пользователя"`
Password string `json:"password" gorm:"not null;default:'';comment:использоватьсемьяпароль"`
Timestamps
SoftDeletes
}
существовать bootstrap/db.go
файл, написатьбаза данныхповерхностьинициализациякод
func initMySqlGorm() *gorm.DB {
// ...
if db, err := gorm.Open(mysql.New(mysqlConfig), &gorm.Config{
DisableForeignKeyConstraintWhenMigrating: true, // Запрещать автоматическое создание ограничений внешнего ключа
Logger: getGormLogger(), // делатьиспользовать Настроить Logger
}); err != nil {
return nil
} else {
sqlDB, _ := db.DB()
sqlDB.SetMaxIdleConns(dbConfig.MaxIdleConns)
sqlDB.SetMaxOpenConns(dbConfig.MaxOpenConns)
initMySqlTables(db)
return db
}
}
// база данныхповерхностьинициализация
func initMySqlTables(db *gorm.DB) {
err := db.AutoMigrate(
models.User{},
)
if err != nil {
global.App.Log.Error("migrate table failed", zap.Any("err", err))
os.Exit(0)
}
}
существовать global/app.go
, писать:
package global
import (
"github.com/spf13/viper"
"go.uber.org/zap"
"gorm.io/gorm"
"jassue-gin/config"
)
type Application struct {
ConfigViper *viper.Viper
Config config.Configuration
Log *zap.Logger
DB *gorm.DB
}
var App = new(Application)
существовать main.go
позвонитьбаза данныхинициализацияфункция
package main
import (
"github.com/gin-gonic/gin"
"jassue-gin/bootstrap"
"jassue-gin/global"
"net/http"
)
func main() {
// инициализация Конфигурация
bootstrap.InitializeConfig()
// инициализациябревно
global.App.Log = bootstrap.InitializeLog()
global.App.Log.Info("log init success!")
// Инициализировать базу данных
global.App.DB = bootstrap.InitializeDB()
// Прежде чем закрыть программу, освободите базу данныхсоединять defer func() {
if global.App.DB != nil {
db, _ := global.App.DB.DB()
db.Close()
}
}()
r := gin.Default()
// тестовая маршрутизация
r.GET("/ping", func(c *gin.Context) {
c.String(http.StatusOK, "test gorm")
})
// запускатьсервер r.Run(":" + global.App.Config.App.Port)
}
запускать main.go
, так как я еще не создал go-test
базу данных и скорректированы logger.Writer
для lumberjack
,Таким образом, он будет генерировать storage/logs/sql.log
файл, содержимое файла следующее:
2021/10/13 19:17:47 /Users/sujunjie/go/src/jassue-gin/bootstrap/db.go:44
[error] failed to initialize database, got error Error 1049: Unknown database 'go-test'
создавать go-test
база данных,сновазапускать main.go
,users
поверхностьсоздаватьуспех。