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查看连接进程:
可以看到有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的错误。多请求几次后连接池会重新打开新连接这时候就没有问题了。关于这个问题自己有初步的解决方法,但是感觉不太完美,下次再放上来。
<!-- 336x280 --> <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>转载请注明:快乐编程 » golang go-sql-drive mysql连接池的实现
相关推荐
官方离线安装包,亲测可用。使用rpm -ivh [rpm完整包名] 进行安装
【标题】"Go-go-ole-golang的Win32OLE实现"主要涉及到的是在Go语言中如何使用`go-ole`库来实现Windows操作系统上的Win32对象链接与嵌入(OLE)技术。OLE是微软在Windows平台上实现的一个组件对象模型(COM),它允许...
在本文中,我们将深入探讨`go-sql-driver.zip`中包含的`go-sql-driver`,这是一个用于Go语言(Golang)的MySQL数据库驱动。这个驱动程序使得在Go应用程序中与MySQL服务器进行交互变得简单而高效。我们将会讨论其版本...
在Golang中实现AES-256-CBC(Advanced Encryption Standard with a 256-bit key in Cipher Block Chaining mode)是一种常见的加密方法,用于确保数据的安全性。然而,Golang的标准库`crypto/cipher`在处理密钥时...
2. 并发编程:Go语言的goroutine和channel是其并发模型的核心,通过它们,开发者可以轻松实现多任务并行处理,充分利用ARM64架构的多核优势。 3. 性能调优:利用Go的内置性能分析工具,如`pprof`,可以对ARM64上的...
Go-migrate是一个强大的开源库,专为处理Golang应用的数据库迁移而设计。它支持多种主流数据库系统,包括MySQL、PostgreSQL、Cassandra和SQLite,这使得它成为一个灵活且跨平台的解决方案。 首先,让我们详细了解Go...
半成品A Go game written in golang(Semi-finished).zip Java语言写的围棋小游戏。半成品A Go game written in golang(Semi-finished).zip Java语言写的围棋小游戏。半成品A Go game written in golang(Semi-...
golang-db-sql-benchmark流行的Go数据库/ SQL实用程序的基准的集合测试中的数据库database / sql + go-sql-driver / mysql gocraft / dbr Gorp Sqlx Squirrel数据库/ sql SQL golang-db-sql-benchmark A流行的Go...
golang-github-pmezard-go-difflib-unit-test-devel-0-0.9.git792786c.1.el7.x86_64 官方离线安装包,亲测可用
golang-stats-api-handler, Golang cpu,内存,gc等信息api处理程序 golang-stats-api-handlerGolang cpu,内存,gc等信息api处理程序。 安装go get github.com/fukata/golang-stats-api-handler示
Go-sqlmapper是一个针对Golang语言设计的轻量级ORM(Object-Relational Mapping)框架,它的主要目标是简化数据库操作,将数据表中的行映射到Go语言的结构体中,实现数据库与业务逻辑之间的无缝对接。ORM框架在很多...
开源项目-johnnadratowski-golang-neo4j-bolt-driver.zip是一个专注于Go语言的开源项目,由johnnadratowski开发,旨在提供对Neo4J数据库的Bolt协议支持。这个驱动程序使得Go开发者能够高效、稳定地与Neo4J图形数据库...
在Golang这个强大的编程语言中,开发者们常常需要处理各种异步操作和事件驱动的场景。在这种情况下,有一个良好的事件触发器系统是非常重要的。本文将深入探讨“Go-trigger”,一个专为Golang设计的全局事件触发器库...
在本文中,我们将深入探讨如何使用Golang来构建一个包含路由转发、MySQL集成以及Redis连接的应用。我们将重点关注Golang的特性,如路由处理、数据库连接、并发处理(goroutines)以及通道(chan)的使用。 首先,让...
官方离线安装包,亲测可用
创建基本配置驱动器用于创建coreos configdrive的Golang工具安装安装golang go get github.com/fivethreeo/create-basic-configdrivego install github.com/fivethreeo/create-basic-configdrive用法确保在Linux中...
在Go语言中,集通常使用map实现,其中key是元素,value通常是固定的值,例如true。这是因为Go的map本身提供了高效的查找、插入和删除操作。`golang-set`库可能也遵循这一设计,利用map的特性来构建高效集。 `...
golang-github-davecgh-go-spew-unit-test-0-0.11.git6d21280.1.el7.x86_64.rpm官方离线安装包,亲测可用
golang-github-go-ini-ini-unit-test-devel-1.39.3-0.1.gitf55231c.el7.x86_64.rpm 官方离线安装包,亲测可用
golang-github-davecgh-go-spew-devel-0-0.11.git6d21280.1.el7.noarch.rpm 官方离线安装包,亲测可用