连接数据库
下面是某个博客网站使用gorm连接mysql的代码片段。
if DB, err := gorm.Open(mysql.New(mysqlConfig), &gorm.Config{Logger: newLogger}); err == nil {
sqlDB, _ := DB.DB()
sqlDB.SetMaxOpenConns(global.CONFIG.MySQLConfig.MaxOpenConns) // 设置数据库最大连接数
sqlDB.SetMaxIdleConns(global.CONFIG.MySQLConfig.MaxIdleConns) // 设置上数据库最大闲置连接数
global.DB = DB
} else {
panic("connect server failed")
}
gorm.Open()
需要两个参数,一个是关于mysql的相关配置,另一个是gorm的相关配置。gorm.Open()
的作用就是连接数据库,初始化一些配置信息,并返回一个gorm.DB
结构体,这个结构体封装了GORM框架所有的数据库操作方法。
gorm.DB
这个结构体的内容如下:
type DB struct {
*Config
Error error
RowsAffected int64
Statement *Statement
clone int
}
gorm.DB
这个结构体的第一个变量是一个指针,指向gorm包里面的Config结构体,这个结构体的主要作用就是可以自定义设置数据库的一些配置信息。比如关于事务、表名、外键、创建时间、预编译等配置信息可以自定义配置,如果不去配置这些信息就会使用系统默认的配置。关于这个Config结构体详见这几篇博客文章:
- Gorm之gorm.Config结构体字段详解(CSDN)
- GORM 配置(官方文档)
对代码中sqlDb, _ := DB.DB()的理解如下:DB这个结构体封装了GORM框架所有的数据库操作方法。但是为什么需要使用sqlDb对象来操作连接池呢?用DB对象不行吗?DB()方法的源代码如下所示:
// DB returns `*sql.DB`
func (db *DB) DB() (*sql.DB, error) {
connPool := db.ConnPool
if dbConnector, ok := connPool.(GetDBConnector); ok && dbConnector != nil {
return dbConnector.GetDBConn()
}
if sqldb, ok := connPool.(*sql.DB); ok {
return sqldb, nil
}
return nil, ErrInvalidDB
}
从源码中可以看到,该方法的接收者是gorm包里面的bd对象(该对象的类型就是前面讲的DB结构体类型),但返回值是sql包里面的DB类型(并不是gorm包里面的DB类型)。再来看看sql包里面的DB类型是什么样子:
type DB struct {
// Atomic access only. At top of struct to prevent mis-alignment
// on 32-bit platforms. Of type time.Duration.
waitDuration int64 // Total time waited for new connections.
connector driver.Connector
// numClosed is an atomic counter which represents a total number of
// closed connections. Stmt.openStmt checks it before cleaning closed
// connections in Stmt.css.
numClosed uint64
mu sync.Mutex // protects following fields
freeConn []*driverConn // free connections ordered by returnedAt oldest to newest
connRequests map[uint64]chan connRequest
nextRequest uint64 // Next key to use in connRequests.
numOpen int // number of opened and pending open connections
// Used to signal the need for new connections
// a goroutine running connectionOpener() reads on this chan and
// maybeOpenNewConnections sends on the chan (one send per needed connection)
// It is closed during db.Close(). The close tells the connectionOpener
// goroutine to exit.
openerCh chan struct{}
closed bool
dep map[finalCloser]depSet
lastPut map[*driverConn]string // stacktrace of last conn's put; debug only
maxIdleCount int // zero means defaultMaxIdleConns; negative means 0
maxOpen int // <= 0 means unlimited
maxLifetime time.Duration // maximum amount of time a connection may be reused
maxIdleTime time.Duration // maximum amount of time a connection may be idle before being closed
cleanerCh chan struct{}
waitCount int64 // Total number of connections waited for.
maxIdleClosed int64 // Total number of connections closed due to idle count.
maxIdleTimeClosed int64 // Total number of connections closed due to idle time.
maxLifetimeClosed int64 // Total number of connections closed due to max connection lifetime limit.
stop func() // stop cancels the connection opener.
}
上面sql包里面的DB结构体的大致内容就是关于数据库的连接数量,连接状态和时间等信息。那么现在回到DB()方法里面。该方法的主要功能就是创建一个连接池,然后就能通过一些参数来设置连接池或者关闭连接。下面是一些网上博主的观点:
创建gorm.DB对象的时候连接并没有被创建,在具体使用的时候才会创建。gorm内部,准确的说是
database/sql
内部会维护一个连接池,可以通过参数设置最大空闲连接数,连接最大空闲时间等。使用者不需要管连接的创建和关闭。
以上就对gorm的连接做了一个大致的分析,由于数据库底层驱动,引擎这些底层原理还没有怎么了解过,所以上面的解释也不是很深入。
mysql.Config的各个字段
MySQL 驱动程序提供了一些配置可以在初始化过程中使用
type Config struct {
DriverName string
ServerVersion string
DSN string
DSNConfig *mysql.Config
Conn gorm.ConnPool
SkipInitializeWithVersion bool
DefaultStringSize uint
DefaultDatetimePrecision *int
DisableWithReturning bool
DisableDatetimePrecision bool
DontSupportRenameIndex bool
DontSupportRenameColumn bool
DontSupportForShareClause bool
DontSupportNullAsDefaultValue bool
DontSupportRenameColumnUnique bool
}
DSN(数据源名称)只是连接数据库的其中一个参数,通过这一个参数就能连接数据库。像其他参数,比如
DriverName:可以自定义驱动名;
Conn:可以通过一个现有的数据库连接来初始化 *gorm.DB;
SkipInitializeWithVersion:是否根据当前 MySQL 版本自动配置
DefaultStringSize:为字符串(string)字段设置大小。默认情况下,对于没有大小、没有主键、没有定义索引且没有默认值的字段,将使用db类型“longext”
DisableDatetimePrecision:禁用日期时间精度支持。但是这在MySQL 5.6之前不支持
DefaultDatetimePrecision:默认日期时间精度。比如:DefaultDatetimePrecision:&datetimePrecision
DontSupportRenameIndex:重命名索引时删除并创建索引。但是在MySQL 5.7、MariaDB之前不支持重命名索引
DontSupportRenameColumn:重命名列时使用change。但是在MySQL 8、MariaDB之前不支持重命名
其他的字段用的非常少,当有需要的时候在去研究。