Skip to content
On this page

连接数据库

  • GORM官方支持的数据库类型有:MySQLPostgreSQLSQliteSQL Server

连接Mysql数据库

项目初始化

shell
go mod init gorm-related
  • 项目目录
shell
.
├── config
   └── db.yaml # 配置文件
├── go.mod
├── go.sum
└── main.go // 入口文件
  • 配置文件:config/db.yaml
yaml
mysql:
  db1:
    username: root
    password: study_student
    host: 127.0.0.1
    port: 1000
    dbName: lyb

下载依赖

shell
# 连接数据库使用
go get -u gorm.io/gorm
go get -u gorm.io/driver/mysql
# 读取mysql yaml配置
go get -u github.com/spf13/viper

连接数据库

  • 拆分为下面三步:

读取yamlmysql配置

Go
type DatabaseConfig struct {
	Username string
	Password string
	Host     string
	Port     int
	DBName   string
}

// 获取数据库配置
func loadDbConfig(configFile string) (*DatabaseConfig, error) {
	viper.SetConfigFile(configFile)
	err := viper.ReadInConfig()
	if err != nil {
		return nil, fmt.Errorf("failed to read config file: %w", err)
	}
	var config DatabaseConfig
	err = viper.UnmarshalKey("mysql.db1", &config)
	if err != nil {
		return nil, fmt.Errorf("failed to unmarshal config: %w", err)
	}
	return &config, nil
}

根据配置生成连接DSN(Data Source Name)

Data Source Name 格式如下

Go
[username[:password]@][protocol[(address)]]/dbname[?param1=value1&...&paramN=valueN]

Data Source Name 一些例子

TIP

  • 要支持完整的UTF-8编码,需要将charset=utf8更改为charset=utf8mb4

  • parseTime=true支持把数据库datetimedate类型转换为golangtime.Time类型

  • loc=Local使用系统本地时区

  • timeout 数据库连接超时时间,例如timeout=10s

  • readTimeout 读超时时间,0代表不限制

  • writeTimeout 写超时时间,0代表不限制

Go
//mysql dsn格式
//涉及参数:
//username   数据库账号
//password   数据库密码
//host       数据库连接地址,可以是Ip或者域名
//port       数据库端口
//Dbname     数据库名
username:password@tcp(host:port)/Dbname?charset=utf8mb4&parseTime=True&loc=Local

//填上参数后的例子
//username = admin
//password = 258369
//host     = 127.0.0.1
//port     = 1000
//Dbname   = gorm
//后面K/V键值对参数含义为:
//  charset=utf8mb4 客户端字符集为utf8mb4(要支持完整的UTF-8编码,需要将charset=utf8更改为charset=utf8mb4
//  parseTime=true 支持把数据库datetime和date类型转换为golang的time.Time类型
//  loc=Local 使用系统本地时区
admin:258369@tcp(127.0.0.1:1000)/gorm?charset=utf8mb4&parseTime=True&loc=Local

//gorm 设置mysql连接超时参数
//开发的时候经常需要设置数据库连接超时参数,gorm是通过dsn的timeout参数配置
//例如,设置10秒后连接超时,timeout=10s
//下面是完成的例子
admin:258369@tcp(127.0.0.1:1000)/gorm?charset=utf8mb4&parseTime=True&loc=Local&timeout=10s

//设置读写超时时间
// readTimeout - 读超时时间,0代表不限制
// writeTimeout - 写超时时间,0代表不限制
admin:258369@tcp(127.0.0.1:1000)/gorm?charset=utf8mb4&parseTime=True&loc=Local&timeout=10s&readTimeout=30s&writeTimeout=60s

代码

Go
// 生成连接数据库链接
func genDbUrl(config *DatabaseConfig) string {
	return fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local", config.Username, config.Password, config.Host, config.Port, config.DBName)
}

连接数据库

Go
// 连接数据库
func connectToDb(dbUrl string) (*gorm.DB, error) {
	db, err := gorm.Open(mysql.Open(dbUrl), &gorm.Config{})
	if err != nil {
		return nil, fmt.Errorf("failed to connect to MySQL database: %w", err)
	}
	return db, nil
}
  • 完整代码
Go
package main

import (
	"fmt"
	"log"

	"github.com/spf13/viper"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

type DatabaseConfig struct {
	Username string
	Password string
	Host     string
	Port     int
	DBName   string
}

// 获取数据库配置
func loadDbConfig(configFile string) (*DatabaseConfig, error) {
	viper.SetConfigFile(configFile)
	err := viper.ReadInConfig()
	if err != nil {
		return nil, fmt.Errorf("failed to read config file: %w", err)
	}
	var config DatabaseConfig
	err = viper.UnmarshalKey("mysql.db1", &config)
	if err != nil {
		return nil, fmt.Errorf("failed to unmarshal config: %w", err)
	}
	return &config, nil
}

// 生成连接数据库链接
func genDbUrl(config *DatabaseConfig) string {
	return fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local", config.Username, config.Password, config.Host, config.Port, config.DBName)
}

// 连接数据库
func connectToDb(dbUrl string) (*gorm.DB, error) {
	db, err := gorm.Open(mysql.Open(dbUrl), &gorm.Config{})
	if err != nil {
		return nil, fmt.Errorf("failed to connect to MySQL database: %w", err)
	}
	return db, nil
}

func main() {
	// 获取数据库配置
	dbConfig, err := loadDbConfig("config/db.yaml")
	if err != nil {
		log.Fatalf("Failed to load config: %v", err)
	}
	// 根据数据库配置获取url
	dbUrl := genDbUrl(dbConfig)
	// 根据生产的url连接数据库
	db, connectErr := connectToDb(dbUrl)
	if connectErr != nil {
		log.Fatalf("Failed to connect to MySQL database: %v", connectErr)
	}
	fmt.Println("Successfully connected to MySQL database!", db)
}

高级配置

日志配置

  • 日志级别有SilentErrorWarnInfo

  • Gorm有一个默认 logger实现,默认情况下,它会打印慢SQL错误

  • 可以在初始化时自定义它,会改变全局日志规则

Go
newLogger := logger.New(
  log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer
  logger.Config{
    SlowThreshold:              time.Second,   // Slow SQL threshold 慢sql阀值
    LogLevel:                   logger.Info, // Log level 日志级别
    IgnoreRecordNotFoundError: true,           // Ignore ErrRecordNotFound error for logger 忽略ErrRecordNotFound(记录未找到)错误
    ParameterizedQueries:      true,           // Don't include params in the SQL log 不要在 SQL 日志中包含参数
    Colorful:                  false,          // Disable color 关闭颜色
  },
)
db, err := gorm.Open(mysql.Open(dbUrl), &gorm.Config{
  Logger: newLogger
})
  • 修改一个连续会话日志
Go
// Continuous session mode
tx := db.Session(&Session{Logger: newLogger})
tx.First(&user)
tx.Model(&user).Update("Age", 18)
  • Debug单个操作,将当前操作log级别调整为logger.Info
Go
DB.Debug().AutoMigrate(&User{})

Debug方法原理如下

Go
// Debug start debug mode
func (db *DB) Debug() (tx *DB) {
	tx = db.getInstance()
	return tx.Session(&Session{
		Logger: db.Logger.LogMode(logger.Info),
	})
}