database/sql
最主要还是实现了连接池逻辑- go源码版本: v1.16
- 源码仓库: https://github.com/golang/go/tree/go1.16.6/src/database/sql
Open会返回DB对象并开启一条connectionOpener线程
- connectionOpener主要处理下面提到的”当前连接数大于maxOpen会陷入等待”的连接资源请求
DB的核心方法: conn(ctx context.Context, strategy connReuseStrategy) (*driverConn, error)
- 优先返回连接池里的连接
- 当前连接数大于maxOpen会陷入等待, 等待取决于ctx, 也即由调用方控制
- 其余情况则返回一个新连接
DB的连接池: freeConn []*driverConn
DB的核心方法: putConnDBLocked(conn, err) bool
- 如果当前连接数大于maxOpen则直接返回false, 上层看到false则直接关闭该连接conn
- 优先满足正在等待连接资源请求的(connRequests是一个map,可以看出请求连接资源并无优先级的说法)
- 如果MaxIdleConns < len(freeConn), 即连接池满了, 则直接返回false, 上层看到false则直接关闭该连接conn
- 否则丢到连接池freeConn中
清理线程(connectionCleaner):
- SetConnMaxLifetime,SetConnMaxIdleTime时才会去起唯一的一条清理线程
- 清理线程定期清理连接池freeConn的连接, 根据maxLifetime和createAt清理, 也根据maxIdleTime和returnedAt清理
- 有趣的是清理线程并不理会MaxOpen和MaxIdleConns是多少, 只关注MaxLifetime和MaxIdleTime, 反正过期了就清理
sql执行方法如Query,Exec,Ping等, 都会先去调conn获取连接, 再用其连接执行sql, 最后将putConnDBLocked(conn), (query是等rows全部scan完close再putConnDBLocked(conn))
关于resetSession最终的去处, 总的来说就是reset了个寂寞, 最终居然只是
conn.SetReadDeadline(time.Time{})
?