首页 > 数据库 >golang go-sql-drive mysql连接池的实现

golang go-sql-drive mysql连接池的实现

时间:2023-01-05 22:33:11浏览次数:56  
标签:rows http err db drive golang sql 连接池


​http://www.01happy.com/golang-go-sql-drive-mysql-connection-pooling/​

golang内部自带了连接池功能,刚开始接触golang的时候不了解这个,还自己搞了一个 sql.Open的对象管理池,真的非常囧啊。

sql.Open函数实际上是返回一个连接池对象,不是单个连接。在open的时候并没有去连接数据库,只有在执行query、exce方法的时候才会去实际连接数据库。在一个应用中同样的库连接只需要保存一个sql.Open之后的db对象就可以了,不需要多次open。

golang中关于mysql的增删改查我在前面的一篇文章中有说明了,不了解的小伙们可以先去了解一下:​​golang连接mysql操作示例增删改查​

因为普通程序执行完毕之后资源就会被释放掉,所以这里尝试使用web服务进行演示。

开启web服务

首页先启动一个web服务监听9090端口,比较简单不多做说明。



func startHttpServer() {
http.HandleFunc("/pool", pool)
err := http.ListenAndServe(":9090", nil)
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}



db对象初始化

声明一个全局的db对象,并进行初始化。



var db *sql.DB

func init() {
db, _ = sql.Open("mysql", "root:@tcp(127.0.0.1:3306)/test?charset=utf8")
db.SetMaxOpenConns(2000)
db.SetMaxIdleConns(1000)
db.Ping()
}



连接池的实现关键在于SetMaxOpenConns和SetMaxIdleConns,其中:

SetMaxOpenConns用于设置最大打开的连接数,默认值为0表示不限制。
SetMaxIdleConns用于设置闲置的连接数。

设置最大的连接数,可以避免并发太高导致连接mysql出现too many connections的错误。设置闲置的连接数则当开启的一个连接使用完成后可以放在池里等候下一次使用。

请求方法

上面开启http请求设置了请求/pool地址的执行方法



func pool(w http.ResponseWriter, r *http.Request) {
rows, err := db.Query("SELECT * FROM user limit 1")
defer rows.Close()
checkErr(err)

columns, _ := rows.Columns()
scanArgs := make([]interface{}, len(columns))
values := make([]interface{}, len(columns))
for j := range values {
scanArgs[j] = &values[j]
}

record := make(map[string]string)
for rows.Next() {
//将行数据保存到record字典
err = rows.Scan(scanArgs...)
for i, col := range values {
if col != nil {
record[columns[i]] = string(col.([]byte))
}
}
}

fmt.Println(record)
fmt.Fprintln(w, "finish")
}

func checkErr(err error) {
if err != nil {
fmt.Println(err)
panic(err)
}
}



pool方法就是从user表中查出一条记录然后存放到map中,最后输出finish。代码到这里就算完了非常简单,下面来测试一下。首先启动http服务,然后使用ab进行并发测试访问:



$ ab -c 100 -n 1000 'http://localhost:9090/pool'


在数据库中通过show processlist查看连接进程:




golang数据库连接池



可以看到有100来个进程。

因为避免了重复创建连接,所以使用连接池可以很明显的提高性能。有兴趣的童靴可以去掉连接池代码自己测试一下。完整代码如下:



//数据库连接池测试
package main

import (
"database/sql"
"fmt"
_ "github.com/go-sql-driver/mysql"
"log"
"net/http"
)

var db *sql.DB

func init() {
db, _ = sql.Open("mysql", "root:@tcp(127.0.0.1:3306)/test?charset=utf8")
db.SetMaxOpenConns(2000)
db.SetMaxIdleConns(1000)
db.Ping()
}

func main() {
startHttpServer()
}

func startHttpServer() {
http.HandleFunc("/pool", pool)
err := http.ListenAndServe(":9090", nil)
if err != nil {
log.Fatal("ListenAndServe: ", err)
}
}

func pool(w http.ResponseWriter, r *http.Request) {
rows, err := db.Query("SELECT * FROM user limit 1")
defer rows.Close()
checkErr(err)

columns, _ := rows.Columns()
scanArgs := make([]interface{}, len(columns))
values := make([]interface{}, len(columns))
for j := range values {
scanArgs[j] = &values[j]
}

record := make(map[string]string)
for rows.Next() {
//将行数据保存到record字典
err = rows.Scan(scanArgs...)
for i, col := range values {
if col != nil {
record[columns[i]] = string(col.([]byte))
}
}
}

fmt.Println(record)
fmt.Fprintln(w, "finish")
}

func checkErr(err error) {
if err != nil {
fmt.Println(err)
panic(err)
}
}



小结

golang这边实现的连接池只提供了SetMaxOpenConns和SetMaxIdleConns方法进行连接池方面的配置。在使用的过程中有一个问题就是数据库本身对连接有一个超时时间的设置,如果超时时间到了数据库会单方面断掉连接,此时再用连接池内的连接进行访问就会出错。



packets.go:32: unexpected EOF
packets.go:118: write tcp 192.168.3.90:3306: broken pipe



上面都是错误都是go-sql-drive本身的输出,有的时候还会出现bad connection的错误。多请求几次后连接池会重新打开新连接这时候就没有问题了。关于这个问题自己有初步的解决方法,但是感觉不太完美,下次再放上来。


<iframe id="aswift_1" style="border-radius: 2px; border: 1px solid rgba(0, 0, 0, 0); left: 0px; top: 0px; position: absolute; box-shadow: 0px 0px 0px rgba(0,0,0,0);" name="aswift_1" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" width="336" height="280"></iframe>

标签:rows,http,err,db,drive,golang,sql,连接池
From: https://blog.51cto.com/kenkao/5991984

相关文章

  • golang中tcp socket粘包问题和处理
    ​​http://www.01happy.com/golang-tcp-socket-adhere/​​在用golang开发人工客服系统的时候碰到了粘包问题,那么什么是粘包呢?例如我们和客户端约定数据交互格式是一个json......
  • sqlite3的使用,包括连接qt
    一、sqlite比较轻量级数据库二、类型:关系型数据库三、linux系统一般自带四、创建数据库1、在你要创建的数据的文件夹下打开cmd2、执行:sqlite3testBase.db ......
  • android SQLite使用SQLiteOpenHelper类对数据库进行操作
    一、SQLite介绍 SQLite是android内置的一个很小的关系型数据库。 SQLite的官网是http://www.sqlite.org/,可以去下载一些文档或相关信息。 博客中有一篇有稍......
  • SQL Server技术问题之触发器优缺点
    优点:1.强化约束:强制复杂业务的规则和要求,能实现比check语句更为复杂的约束。2.跟踪变化:触发器可以侦测数据库内的操作,从而禁止数据库中未经许可的更新和变化。......
  • PG中级证书到手,PostgreSQL(PG)认证
    PGCCC的PCA(初级)第13营、14营、15营、16营和PCP(中级)第13营参加PostgreSQL能力认证的学员,已经陆续能够查到并下载证书,恭喜他们获得“工业和信息化部与考试中心(软考权威发证......
  • mybatis使用postgresql中的jsonb数据类型
    最近新开发的一个功能使用到postgresql中的jsonb数据类型。架构师可能考虑到这种数据格式更加便于存储json格式的数据,因此考虑使用这种数据类型。自己以前未曾使用过这......
  • 一步一步学爬虫(4)数据存储之MySQL存储
    (一步一步学爬虫(4)数据存储之MySQL存储)4.4MySQL存储  关系型数据库是基于关系模型的数据库,而关系模型是通过二维表来保存的,所以它的存储方式就是行列组成的表,每一列是......
  • MySQL联合索引
    eg,表t中含有abcde五个字段,a为主键,bcd有联合索引CREATETABLE`t`(`a`intprimarykey,`b`int,`c`int,`d`int,`e`varchar(20))ENGINE=InnoDB;c......
  • Golang服务端开发及微服务架构
    ​​Go语言中使用panic和recover简化错误处理​​​​Go语言中的单元测试及反向代理​​​​Go获取命令行参数及信号量处理​​​​Go各种类型转换及函数的高级用法​​......
  • Ajax+WCF+MySQL实现数据库部署并调用
    ​         最近的数据库课程要求将MySQL数据库部署在服务器上,参考了大佬们的博客后,总结一下。    先放上参考的大佬们的博客。        【原......