百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

Golang DB 连接池用法分析(golang连接数据库)

toyiye 2024-07-04 09:26 29 浏览 0 评论

#Go语言# #数据库# #DBA#

go连接mysql为什么需要 import _ "github.com/go-sql-driver/mysql"

go中import _的作用只执行引入包的init函数,那么go-sql-driver/mysql 的init函数又做了什么,在database/sql 中的drivers map[string]driver.Driver注册引擎 mysql => MySQLDriver{}

// go-sql-driver/mysql/driver.go
func init() {
  sql.Register("mysql", &MySQLDriver{})
}

SetMaxIdleConns/SetMaxOpenConns/SetConnMaxLifetime 设置的值有什么用呢?

  • db.maxLifetime 连接从创建开始存活的时间,mysql默认tcp连接的超时时间 8h
  • db.maxOpen 打开的连接最大数量,超过该数量后,query会被阻塞等待可用连接
  • db.maxIdle 空闲池维持的最大连接数量
  • sql.Open为什么只需要一次调用即可?

    1. 加载驱动程序 go-sql-driver/mysql
    2. 初始化DB数据结构
    3. 构造创建连接channel/重置连接channel

    这里并有实际去和数据建立连接,也没有对数据库连接的参数校验,只是初始化了DB结构体,DB结构体中已经包含了连接池 freeConn []*driverConn, 没有必要多次调用open,全局维护一个DB即可,如果需要验证 账户密码/网络是否能通信,需要调用ping来检测。

    type DB struct {
      waitDuration int64 // 统计每次链接的等待时间
    
      connector driver.Connector
    
      // 已经关闭的连接数量
      numClosed uint64
    
      mu sync.Mutex
    
      freeConn     []*driverConn               // 空闲池
      connRequests map[uint64]chan connRequest // 等待连接队列,当前连接达到maxOpen时,就无法不在创建连接,创建一个请求的channel入队列并等待并阻塞当前goroutine
      nextRequest  uint64                      // connRequests[] 指向下一个坑位
      numOpen      int                         // 正在使用的连接数量
    
      // channel 通过此channel来接受建立新的session连接
      // DB.connectionOpener for select 接收channel
      openerCh          chan struct{}
      resetterCh        chan *driverConn       // 重置session以便其他query复用当前session
      closed            bool                   // 标记是否已经关闭链接
      dep               map[finalCloser]depSet //
      lastPut           map[*driverConn]string // 调试用
      maxIdle           int                    // 维持的最大空闲连接数,小于等于0使用defaultMaxIdleConns(2)
      maxOpen           int                    // 维持的最大连接数,0无限制
      maxLifetime       time.Duration          // 连接可以重用的最长时间
      cleanerCh         chan struct{}
      waitCount         int64 // 等待连接的总数
      maxIdleClosed     int64 // 由于空闲而连接的总数
      maxLifetimeClosed int64 // 连接存活时间超过maxLifetime而关闭的时间
    
      stop func() // 取消接收 建立连接channel(openerCh)/重置session channel(resetterCh)
    }

    如果获取数据连接池的状态?当前的连接总数,SetMaxOpenConns/SetMaxIdleConns的数量是否合适。

    使用db.Stats可以查看当前连接池的一些状态,这边返回了一个DBStats结构体,一起看下:

    type DBStats struct {
      MaxOpenConnections int // 打开的最大连接数,包含已经关闭了的连接
    
      // 连接池状态
      OpenConnections int // 当前建立连接的数量,包括正在使用和空闲的数量
      InUse           int // 正在使用的连接数
      Idle            int // 已建立连接,空闲中的连接数
    
      // 统计
      WaitCount         int64         // 等待连接的总数,这里需要着重关注一下
      WaitDuration      time.Duration // query持续等待连接的总时长
      MaxIdleClosed     int64         // 达到SetMaxIdleConns,而关闭的连接数量
      MaxLifetimeClosed int64         // 达到SetConnMaxLifetime. 而关闭的连接数量
    }
  • WaitCount 着重关注一下,看下是不是有慢查询阻塞了可用的连接数量
  • MaxIdleConns设置的过小,而请求数过多导致,会导致MaxIdleClosed比较大,WaitCount也会比较大
  • 注意:db.Stats不要调用过于频繁,它会对整个DB连接池加锁,过于频繁有一定开销。

    DB.Ping()做了哪些事情?DB是如何从连接池中获取一个可用的连接的?

    1. 获取连接,可以复用连接 (cachedOrNewConn)
    2. 获取一个可用的连接 driverConn复用空闲池中freeConn已有的连接从空闲池中移除第一个连接conn这期间都是有锁的,freeConn是一个切片,是并发不安全的该连接是否在生命周期内 lifetime -- db.SetLifeTime设置的tcp连接存活时间本连接过了生命周期,返回 driver.ErrBadConn返回此conndb.SetMaxOpenConns设置了最大打开的连接数,且当前打开的连接已经达到最大数创建一个等待请求,放入等待队列,阻塞当前goroutine等待超时使用context取消,或者等待直到获取可用的连接ctx取消后还是获取到了连接,放回空闲池获取到可用连接,统计本次阻塞时长,可以注意到如果DB.Stats().WaitDuration大了以后问题就很严重了如果本连接过了生命周期,返回 driver.ErrBadConn返回此Conn封装driver返回的connect到driverConn标记driverConn inUse使用中记录连接创建时间createdAtdb指向连接池真正底层的连接

    源码小细节:

  • 移除切片第一个元素:copy(db.freeConn, db.freeConn[1:])
  • 删除map中的元素: delete(db.connRequests, reqKey)
  • map[key]interface: 也可以使用channel作为key
  • 生命周期判断:createdAt.Add(lifetime).Before(time.now())
  • 参观一下context的用法
  • select {
    // 这里留取消的口
    case <-ctx.Done():
      select {
      // 之前我们分析过select尽量不要加default,单那是for select结构,会造成自旋锁,长期占用M不释放
      // 如果这里不用default它就阻塞一直等待req channel中有connect,这里并不是为了等待,只是为了清理一下channel的connect,防止孤儿connect
      default:
      case ret, ok := <-req:
        //...
      }
      return nil, ctx.Err()
    case ret, ok := <-req:
      // ...
      return ret.conn, ret.err
    }
    
    // 我们在外面如何控制超时呢?
    fun bar(){
      t := time.After(10)
      ctx := context.Background()
      res := make(chan struct{})
      go func() {
        ci, _ := conn(ctx)
        res<-ci
      }()
      select {
      case <-t:
        ctx.Done()
      case ci := <-res:
        if ci != nil {
    
        }
      }
    }

    相关推荐

    为何越来越多的编程语言使用JSON(为什么编程)

    JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

    何时在数据库中使用 JSON(数据库用json格式存储)

    在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

    MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

    前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

    JSON对象花样进阶(json格式对象)

    一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

    深入理解 JSON 和 Form-data(json和formdata提交区别)

    在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

    JSON 语法(json 语法 priority)

    JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

    JSON语法详解(json的语法规则)

    JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

    MySQL JSON数据类型操作(mysql的json)

    概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

    JSON的数据模式(json数据格式示例)

    像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

    前端学习——JSON格式详解(后端json格式)

    JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

    什么是 JSON:详解 JSON 及其优势(什么叫json)

    现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

    PostgreSQL JSON 类型:处理结构化数据

    PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

    JavaScript:JSON、三种包装类(javascript 包)

    JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

    Python数据分析 只要1分钟 教你玩转JSON 全程干货

    Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

    比较一下JSON与XML两种数据格式?(json和xml哪个好)

    JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

    取消回复欢迎 发表评论:

    请填写验证码