Golang GORM实战(二) | 数据库连接的N种方式

2022年4月12日 243点热度 0人点赞 0条评论

这是《Golang GORM实战》系列的第二篇,在这篇文章中我们来了解一下GORM是如何连接不同类型的数据库,以及如何配置连接时的参数。

连接数据库

使用GORM连接数据库还是比较简单的,概括起来就是以下三个步骤:

  1. 引入gorm.io/gorm和对应数据库的驱动库,如gorm.io/driver/sqlite

  2. 调用对应驱动库的Open()或New()函数返回一个实现了gorm.Dialector接口的实例。

  3. 调用gorm.Open()方法传入一个gorm.Dialector接口的实例以初始一个gorm.DB对象。

通过上述三个步骤,最终获取一个gorm.DB对象,我们便可以使用该对象的方法操作数据库,如Create,Delete等方法。

下面我们来看MySQL,PostgreSQL,SQLite,SQL Server等不同数据库是怎么执行上述几个步骤连接数据库的:

MySQL

简单连接

下面是连接mysql数据库最简单的方式,我们只需要定义好dsn便可以了,如下:

import (
  "gorm.io/driver/mysql"
  "gorm.io/gorm"
)

func main() {
  dsn := "user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
  db, err := gorm.Open(mysql.Open(dsn))
}

mysql.New

如果我们在连接数据库时,想进一步配置,则可以使用mysql.New()函数,该函数可以传递一个mysql.Config进行详细配置,如:

dsn := "root:123456@tcp(127.0.0.1:3306)/test?charset=utf8mb4&parseTime=true&loc=UTC"

db, err := gorm.Open(mysql.New(mysql.Config{
 DSN:                       dsn,   // DSN data source name
 DefaultStringSize:         256,   // string 类型字段的默认长度
 DisableDatetimePrecision:  true,  // 禁用 datetime 精度,MySQL 5.6 之前的数据库不支持
 DontSupportRenameIndex:    true,  // 重命名索引时采用删除并新建的方式,MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引
 DontSupportRenameColumn:   true,  // 用 `change` 重命名列,MySQL 8 之前的数据库和 MariaDB 不支持重命名列
 SkipInitializeWithVersion: false, // 根据当前 MySQL 版本自动配置
})) 

如果我们查看mysql.Config,可以更加了解在连接数据库时,还可以配置哪些参数,mysql.Config的源码如下:

type Config struct {
 DriverName                string
 DSN                       string
 Conn                      gorm.ConnPool
 SkipInitializeWithVersion bool
 DefaultStringSize         uint
 DefaultDatetimePrecision  *int
 DisableDatetimePrecision  bool
 DontSupportRenameIndex    bool
 DontSupportRenameColumn   bool
 DontSupportForShareClause bool
}

通过sql.DB初始化*gorm.DB

如果我们自己使用database/sql打开一个数据库连接,那么也可以利用这个已经存在的连接,来初始化一个gorm.DB对象, 如:

package main

import (
 "database/sql"

 "gorm.io/driver/mysql"
 "gorm.io/gorm"
)

func main() {

 db, _ := sql.Open("mysql""root:123456@tcp(localhost:3306)/test?charset=utf8&parseTime=True&loc=Local")

 db,err := gorm.Open(mysql.New(mysql.Config{
  Conn: db,
 }))
}

PostgreSQL

简单连接

import (
  "gorm.io/driver/postgres"//驱动库
  "gorm.io/gorm"
)

dsn := "host=localhost user=gorm password=gorm dbname=gorm port=9920 sslmode=disable TimeZone=Asia/Shanghai"
db, err := gorm.Open(postgres.Open(dsn))

postgres.New

package main

import (
 "gorm.io/driver/postgres"
 "gorm.io/gorm"
)

func main() {
 dsn := "host=localhost user=gorm password=gorm dbname=gorm port=9920 sslmode=disable TimeZone=Asia/Shanghai"
 db, err := gorm.Open(postgres.New(postgres.Config{
  DSN:                  dsn,
  PreferSimpleProtocol: true,
 }))

}

通过sql.DB初始化*gorm.DB

package main

import (
 "database/sql"

 "gorm.io/driver/postgres"
 "gorm.io/gorm"
)

func main() {
 dsn := "host=localhost user=gorm password=gorm dbname=gorm port=9920 sslmode=disable TimeZone=Asia/Shanghai"

 sqlDB, _ := sql.Open("pgx", dsn)

 db, err := gorm.Open(postgres.New(postgres.Config{
  Conn:                 sqlDB,
  PreferSimpleProtocol: true,
 }))

}

SQL Server

简单连接

import (
  "gorm.io/driver/sqlserver"
  "gorm.io/gorm"
)

dsn := "sqlserver://gorm:LoremIpsum86@localhost:9930?database=gorm"
db, err := gorm.Open(sqlserver.Open(dsn))

sqlserver.New

package main

import (
 "gorm.io/driver/sqlserver"
 "gorm.io/gorm"
)

func main() {
 dsn := "sqlserver://gorm:LoremIpsum86@localhost:9930?database=gorm"
 db, err := gorm.Open(sqlserver.New(sqlserver.Config{
  DSN: dsn,
 }))
}

通过sql.DB初始化*gorm.DB

package main

import (
 "database/sql"

 "gorm.io/driver/sqlserver"
 "gorm.io/gorm"
)

func main() {
 dsn := "sqlserver://gorm:LoremIpsum86@localhost:9930?database=gorm"
 sqlDB, _ := sql.Open("sqlserver", dsn)
 db, err := gorm.Open(sqlserver.New(sqlserver.Config{
  Conn: sqlDB,
 }))
}

SQLite

因为SQLite数据库其实只是一个文件而已,所以SQLite的连接非常简单,只需要传入SQLite数据库的文件路径即可,比如我们连接一个在当前目录的gorm.db数据,其连接方式如下:

import (
  "gorm.io/driver/sqlite" //驱动库
  "gorm.io/gorm"
)

db, err := gorm.Open(sqlite.Open("gorm.db"))

另外,连接SQLite数据库时,也可以在内存中创建临时数据库,而需要一个实际的数据库,其连接方式如下所示:

db, err := gorm.Open(sqlite.Open("file::memory:?cache=shared"))

gorm.Config

在上面的示例中,我们都用gorm.Open()打开数据库连接的,我们查看这个方法的源码,如:

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

我们可以看到其实第一个参数外,后面还可以无限传入类型为Option的参数,用于配置连接参数,而Option是一个接口,如下:

// Option gorm option interface
type Option interface {
 Apply(*Config) error
 AfterInitialize(*DB) error
}

gorm.Config实现了Option接口,因此我们可以将gorm.Config传递给gorm.Open函数,gorm.Config的源码

// Config GORM config
type Config struct {
 //跳过默认事务
 SkipDefaultTransaction bool
 // 命名策略,可以定义表名,列表等生成规则
 NamingStrategy schema.Namer
 // 在创建或更新时,是否更新关联数据
 FullSaveAssociations bool
 // 日志接口,用于实现自定义日志
 Logger logger.Interface
 // 创建时间使用的函数
 NowFunc func() time.Time
 // 生成 SQL 但不执行,可以用于准备或测试生成的 SQL
 DryRun bool
 // 是否禁止创建 prepared statement 并将其缓存
 PrepareStmt bool
 // 禁止去ping数据库,检测是否可用
 DisableAutomaticPing bool
 // 是否禁止自动创建外键约束
 DisableForeignKeyConstraintWhenMigrating bool
 // 是否禁止嵌套事务
 DisableNestedTransaction bool
 // 是否允许全局update/delete
 AllowGlobalUpdate bool
 // 执行查询时,是否带上所有字段
 QueryFields bool
 // 默认批量插入大小
 CreateBatchSize int
}

下面是使用gorm.Config的参数来控制数据库连接的示例,如:

dsn := "user:pass@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
    SkipDefaultTransaction:true,
    CreateBatchSize:1000,
})

连接池

通过数据库连接池,我们可以避免频繁创建和销数据库连接所带来的开销,GROM的数据连接池底层是通过database/sql来实现的,所以其设置方法与database/sql是一样的。

sqlDB, err := db.DB()

// SetMaxIdleConns 设置空闲连接池中连接的最大数量
sqlDB.SetMaxIdleConns(10)

// SetMaxOpenConns 设置打开数据库连接的最大数量。
sqlDB.SetMaxOpenConns(100)

// SetConnMaxLifetime 设置了连接可复用的最大时间。
sqlDB.SetConnMaxLifetime(time.Hour)

关闭数据库

程序执行结束后,需要关闭数据连接,而GORM的底层仍然是通过database/sql去连接数据库的,因此要通过gorm.DB对象的DB()方法返回的sql.DB来关闭数据库连接,如:

sqlDB, err := db.DB()

sqlDB.Close()//defer sqlDB.Close()

小结

在这篇文章,我们学习了使用GORM去连接MySQL,PostgreSQL,SQLServer,SQLite等不同数据库的方式,可以看出连接不同的数据的方式大同小异,只是配置(Config)有些许不同,相信你应该已经掌握了吧!

13690Golang GORM实战(二) | 数据库连接的N种方式

root

这个人很懒,什么都没留下

文章评论