GORM 在项目中的初始化、重要连接参数和多数据源配置

科技   2024-11-20 08:55   北京  

这节我们开始给项目框架集成GROM,让项目能访问数据库。本篇内容我们专注Go项目集成GORM的第一阶段,即:Go项目下载和安装GORM的步骤、在项目中的初始化、讲解生产环境使用GORM时要设置哪些必要的参数、如何配置GORM的读写分离以及多数据源。

下篇内容我会教大家怎么让GORM在你的Go项目中变得更好用,通过自己实现GORM Logger 把数据库操作相关的错误、慢查询、操作日志和项目的应用日志整合在一起,同样为GORM日志注入追踪ID,把它们归因到关联的请求上下文中去。

我们项目中使用的版本是GORM V2,在安装和集成的过程中我也会跟大家说一下V2版本与V1在使用上的主要区别。

本节内容节选自我的专栏《Go项目搭建和整洁开发实战》请扫码订阅专栏,除了能参考专栏学习项目搭建的技能,还能结合大量实战场景的代码演练真正掌握代码分层和整洁开发的精髓。

GORM的下载与安装

首先GORM 升级到 V2 以后项目组织发生了变更从 github.com/jinzhu/gorm 变成了 gorm.io/gorm 安装步骤也会跟之前的V1版本有些不同

我们先来安装GORM,边安装边说。

 go get -u gorm.io/gorm

GORM 在V1 版本中各个数据库的驱动是和整个软件包绑定在一起的,所以下载安装一次就行了,但是到了V2之后每种数据库单独提供了驱动,我们使用的是MySQL,所以先把MySQL的驱动安装一下

go get -u  "gorm.io/driver/mysql"
如果你的数据库里用了多数据源,那么你需要把项目用到的每个数据库类型的驱动都先安装上,假如说项目中还使用了 postgres 那么在初始化GORM前也需要把 postgres 的驱动下载下来。
go get -u  "gorm.io/driver/postgres"

之所以安装这个驱动呢,是因为两个版本在初始化数据看连接时的Open 方法有了调整

// V1
func Open(dialect string, args ...interface{}) (db *DB, err error) {}

// V2
func Open(dialector Dialector, opts ...Option) (db *DB, err error) {}

V1 版本我们直接传一个数据库类型的字符串就行了

db, err := gorm.Open("mysql""root:pass@tcp(xxx)/db_name")
if err != nil {
    panic(err)
}

而V2版本需要用到我们刚才安装的驱动

db, err := gorm.Open(
mysql.Open("root:pass@tcp(xxx)/db_name),
&gorm.Config{},
)

初始化GORM

安装完驱动后先不着急去初始化GORM,前面的章节《Go 项目配置的定制化及一体化打包方案》我们给项目做好了配置管理,所以我们得先把配置文件进行一些调整,打开我们的config/application.dev.yaml 文件,添加一些Database相关的配置

database:
  type: mysql
  master:
    dsn: root:superpass@tcp(localhost:30306)/go_mall?xxx...
    maxopen: 100
    maxidle: 10
    maxlifetime: 300000000000
  slave:
    dsn: root:superpass@tcp(localhost:30306)/go_mall?xxx...
    maxopen: 100
    maxidle: 10
    maxlifetime: 300000000000

这里我们配置了主从两个数据库连接的配置,因为我们项目里暂时用不到主从分离,所以就先把主库和从库设置的一样,等实际开发用到主从实例了再去进行相应的修改。这里的参数等到下面初始化GORM的时候再去细讲。

接下来我们在 dal/dao/gorminit.go 中写一个initDB的自定义函数,把用Database配置来初始化GORM DB连接的这部操作抽象提炼到一起

func initDB(option config.DbConnectOption) *gorm.DB {
 db, err := gorm.Open(mysql.Open(option.DSN), &gorm.Config{})
 if err != nil {
  panic(err)
 }
 sqlDb, _ := db.DB()
 sqlDb.SetMaxOpenConns(option.MaxOpenConn)
 sqlDb.SetMaxIdleConns(option.MaxIdleConn)
 sqlDb.SetConnMaxLifetime(option.MaxLifeTime)
 if err = sqlDb.Ping(); err != nil {
  panic(err)
 }
 return db}

生产环境GORM必须设置的连接参数

GORM 使用的是Go的 database/sql 来维护的连接池,这里解释一下创建GORM DB连接时用到的这些参数,我们在配置文件里指定的maxidlemaxopenmaxlifetime 分别传递给了GORM DB的下面三个方法,这三个方法在生产环境时一定要记得设置

  • SetMaxIdleConns(10) 设置最大空闲连接数为10个。
  • SetMaxOpenConns(100) 设置可打开的最大连接数为 100 个。
  • SetConnMaxLifetime 设置一个连接空闲后在多长时间内可复用,上面配置文件里设置的是300000000000, 因为Go的time.Duration底层类型是int64, 一秒是1000000000,这个大家可设置一个适当的时间,一般5~15分钟,不要太长。

Open 方法的第二个参数我们传递了一个 &gorm.Config{} ,里面没有设置任何配置选项

db, err := gorm.Open(mysql.Open(option.DSN), &gorm.Config{})

我们暂时还用不到它,下一节当我们需要把GORM日志整合到应用日志时才会用到它。

读写分离和多数据源配置

读写分离

首先GORM V2 版本支持一个自动按照执行的语句进行读写分离连接切换的功能 DBResolver,但是感觉用起来还是比较麻烦。

这个大家可以自己研究一下,这里为介绍一个在GORM V1时就一直用的土办法,这种方法虽然不支持自动切换,但贵在简单,在写Dao方法时根据逻辑类型选择对应的DB连接即可。

我们在在 dal/dao 的 gorminit.go 文件开头定义好保存主库和读库实例的变量

var _DbMaster *gorm.DB
var _DbSlave *gorm.DB

// DB 返回只读实例
func DB() *gorm.DB {
 return _DbSlave
}

// DBMaster 返回主库实例
func DBMaster() *gorm.DB {
 return _DbMaster
}

为每个变量提供了Getter方法,这样使用起来代码更简洁一些。初始化主库和从库的DB连接时,在init方法中使用上面介绍过的initDB方法,用主从库各自的配置进行初始化。

在写DAO方法时根据逻辑类型选择对应的DB连接使用。

多数据源配置

有的时候你的项目里的数据可能来自不同的数据库,那么现在项目的配置和初始化方法还不支持多数据源。

一开始做项目的时候我确实没有考虑到这个问题,工作中大部分DB用的也是MySQL,所以这里设计的不够灵活,好在咱们读者中已经有人开始在项目中使用起来了,并且还做了多数据源的扩展。

这部分内容订阅后可在项目中查看,关于读写分离、多数据源配置、以及项目集成GORM时还需要做哪些工作才能真正好用。 都可以扫码订阅专栏,加入项目后一起学习。

订阅后可直接用小程序或者PC网页上阅读全部已更新教程,现在已有不少读者把项目应用到工作中,并提了不少实战反馈建议。


总结

从现在开始,项目使用GORM访问数据库做各种操作时完全没有问题的,但还有一个隐患,一旦出现慢SQL或者SQL错误你是没法查到的,因为GORM的Logger默认是把日志输出到控制台的,下一节我们就对这部分其进行定制化,解决这个问题。

专栏入口:https://xiaobot.net/p/golang

网管叨bi叨
分享软件开发和系统架构设计基础、Go 语言和Kubernetes。
 最新文章