记Go "database/sql" 连接池遇到的一个问题

"database/sql" 连接池遇到的一个坑

背景

笔者参与的项目使用到golang语言作为开发语言,在持久层方面,考虑到golang自带的database/sql包已经实现了连接池,因此没有使用开源的orm框架,直接使用sql包做了简单的封装供项目持久层使用。

原生API使用

记Go "database/sql" 连接池遇到的一个问题
记Go "database/sql" 连接池遇到的一个问题
最后封装了CRUD方法提供调用

线上环境遇到的问题

线上偶然看到日志存在bad connection的报错,特别是一些管理端的服务(调用不频繁,超过1天未操作过该服务接口),多次调用异常后,请求又可以恢复正常。

解决方法

上述问题,笔者感觉是数据库连接池失效的原因,项目中翻出上图代码,果然发现获得连接池对象时,并没有设置连接最大存活时间,即调用方法SetConnMaxLifetime。
由于服务端(此时是mysql数据库默认连接超时关闭时间是28800秒),客户端连接池中持有的连接超过这个时间后已经失效,而由于客户端未设置过期时间,导致池中失效的连接依然存在,此时请求过来时,从池中拿出了失效的连接,因此会出现bad connection的异常。此时需要SetConnMaxLifetime设置过期时间
记Go "database/sql" 连接池遇到的一个问题
那为什么多次请求后,请求有开始恢复正常了呢?
原来是因为go连接池实现中,不会将已经过期的连接再放回池中,因此当失效的连接取完后,连接池又或创建新的有效的连接,请求恢复正常!问题解决。