连接池是做网络应用经常用到的一个概念,可以缓存连接减少创建连接的损耗。那么在golang中应该如何做一个连接池,在这里会通过解读<a href="https://golang.org/pkg/database/sql/">database/sql</a>包的连接池实现来给自己一些参考和启发。
首先,需要了解database/sql的基本原理和使用方法,请参考下面的链接仔细阅读:http://go-database-sql.org/overview.html
接下来分析下建立新连接的基本流程:
然后是释放连接的基本流程:
最后,有几个关键函数也想说明一下:
在调用sql.Open的时候,会创建一个协程“go db.connectionOpener()“
// Runs in a separate goroutine, opens new connections when requested.
func (db *DB) connectionOpener() {
for range db.openerCh {
db.openNewConnection()
}
}
那这个函数是做什么用的呢?我们发现有db.openerCh,用到这个channel的函数只有db.maybeOpenNewConnections()函数
func (db *DB) maybeOpenNewConnections() {
numRequests := len(db.connRequests)
if db.maxOpen > 0 {
numCanOpen := db.maxOpen - db.numOpen
if numRequests > numCanOpen {
numRequests = numCanOpen
}
}
for numRequests > 0 {
db.numOpen++ // optimistically
numRequests--
if db.closed {
return
}
db.openerCh <- struct{}{}
}
}
maybeOpenNewConnections只有在创建连接失败或者释放连接失败或者发生error的时候才会调用,这样就能够保证不会有阻塞的获取连接的请求得不到资源。例如释放连接时,发生了错误,此时有阻塞的获取连接请求,如果直接返回,那么等待池会继续阻塞。此时就可以调用maybeOpenNewConnections函数建立新的连接。