Gorm源码学习-数据库连接


1 前言

gorm源码地址: Gorm , 本文基于commit:cef3de694d9615c574e82dfa0b50fc7ea2816f3e

官方入门指南: Doc


 

2 连接数据库代码示例

目前Gorm官方支持的数据库类型有:MySQL, PostgreSQL, SQLite, SQL Server. 

目前Go官方支持MySQL驱动

下面来看连接MySQL的数据库的基本代码


 
  package main
   
  import (
  "fmt"
  "time"
   
  "gorm.io/driver/mysql"
  "gorm.io/gorm"
  )
   
  func main() {
  // 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情
  dsn := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?timeout=%s&readTimeout=%s&writeTimeout=%s",
  "root", "zbwmysql", "127.0.0.1", "3306", "user_db", "100ms", "2s", "3s")
  db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
  if err != nil {
  fmt.Printf("gorm open fail, err:%v dsn:%v/n", err, dsn)
  }
  mysqlDB, err := db.DB()
  if err != nil {
  fmt.Printf("get mysql db fail, err:%v/n", err)
  }
  // 参考 https://github.com/go-sql-driver/mysql#important-settings 获取详情
  mysqlDB.SetConnMaxLifetime(time.Minute * 3) // 客户端将空闲连接主动断开的超时时间,官方建议小于5分钟
  mysqlDB.SetMaxOpenConns(10) // 取决于服务器的配置
  mysqlDB.SetMaxIdleConns(10) // 官方建议和SetMaxOpenConns相同
  }

这里有必要看下 timeoutreadTimeoutwriteTimeoutSetConnMaxLifetime 三个参数

timeout是指 建立连接的一个超时时间

readTimeout是指 I/O 读操作的超时时间

writeTimeout是指 I/O 写操作的超时时间

SetConnMaxLifetime 是指客户端将空闲连接主动断开的超时时间,

如果设置为0,则连接池的连接将这一直被复用,但是系统会主动将长时间的连接杀掉,

因此若客户端再次使用长时间空闲的连接将会报错,driver: bad connection

 

问题的修复记录,可以看 issues-1120 

 

 3 连接数据库代码分析

从上一节看,Gorm连接数据库的过程只需要调用一个函数,

func Open(dialector Dialector, opts ...Option) (db *DB, err error)

 但是Gorm目前是MySQL, PostgreSQL, SQLite, SQL Server,四种类型的数据库的,这个是怎么做到的呢?

 这就需要具体看下请求参数Dialector 和 返回参数DBOpen函数内部实现

 首先让我们先看看Golang的interface类型

 

3.1 interface理解

An interface type is defined as a set of method signatures.

A value of interface type can hold any value that implements those methods.

A type implements an interface by implementing its methods. There is no explicit declaration of intent, no "implements" keyword.

 以上摘抄自A Tour of Go , interface是一种包含方法定义的类型,通过实现该interface的所有方法来隐式实现该接口。

 3.2 Dialector接口定义
Dialector定义如下,这里对部分方法加了注释,方便理解。


 
  // Dialector GORM database dialector
  type Dialector interface {
  Name() string // 驱动名称
  Initialize(*DB) error // 初始化连接
  Migrator(db *DB) Migrator
  DataTypeOf(*schema.Field) string // 类型映射
  DefaultValueOf(*schema.Field) clause.Expression // 类型默认值
  BindVarTo(writer clause.Writer, stmt *Statement, v interface{})
  QuoteTo(clause.Writer, string)
  Explain(sql string, vars ...interface{}) string // SQL语句格式化输出
  }

不仅仅Mysql驱动,PostgreSQL, SQLite, SQL Server驱动都得实现Dialector中定义的全部方法。

并且这些方法恰恰是不同数据库的区别所在,比如不同数据库的数据类型是有差异的,即使含义相同,写法也可能不同,

因此gorm的数据类型映射到不同数据库能识别的类型,这就是DataTypeOf实现的功能。

可以在go-gorm找到各种数据库的Dialector实现,如PostgreSQL Dialector,MySQL Dialector 

 

3.3 DB结构体定义

DB定义如下,这里对部分方法加了注释,方便理解。


 
  // DB GORM DB definition
  type DB struct {
  *Config // 连接及其连接相关信息等
  Error error
  RowsAffected int64
  Statement *Statement // SQL语句执行相关信息
  clone int
  }

 其中,Config中会保留连接ConnPool 、CRUD相关的函数callbacks等信息,部分代码代码如下,完整代码见gorm.Config


 
  // Config GORM config
  type Config struct {
  // ClauseBuilders clause builder
  ClauseBuilders map[string]clause.ClauseBuilder
  // ConnPool db conn pool
  ConnPool ConnPool
  // Dialector database dialector
  Dialector
  // Plugins registered plugins
  Plugins map[string]Plugin
   
  callbacks *callbacks
  cacheStore *sync.Map
  }

看了Open函数的请求参数和返回参数,接下来我们看看内部的具体实现

本站声明:
1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;

2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;

3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;

4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;

5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/tech/database/293375.html

(0)
上一篇 2022年11月22日 13:53
下一篇 2022年11月22日 14:13

相关推荐

发表回复

登录后才能评论