Golang - 原生go-sql-driver:出现invalid connection报错

在使用go-sql-driver/msqyl驱动过程中,偶现invalid connection错误,字面上看就是无效连接的意思。

开始以为是数据库压力问题或是网络不好,后来发现服务器和数据库是走内网的,网络出现问题几率非常小;只是在测试服务器上跑,没多少连接,不存在压力问题。

golang数据库驱动维护一个连接池,如果连接池中的连接超过这个生存时间,就会被主动释放(关闭),但如果这个生存时间超过服务端设置的超时时间,服务端在比客户端先关闭连接,客户端这边拿出连接池中无效的连接(服务端已主动关闭)来使用,当发起请求时,就会出现无效连接错误invalid connection。

原因:客户端(比如:代码层面)连接数据库后,客户端并没有在访问后立即执行close(),通常会作为全局实例缓存起来,方便直接调用;而mysql服务端中有超时配置,当超时后,服务端主动关闭服务,这样就会导致下次访问出现无效连接的错误。

解决思路是客户端连接的最大生存时间要小于服务端的超时时间——可以修改客户端的代码或修改数据库服务端的配置。

查看数据库服务端超时配置:

show variables like "wait_timeout%";

 解决方案:(客户端,代码层面)

db.DB().SetConnMaxLifetime(time.Hour*4)      //客户端的超时时间【连接的最大生命周期】,要小于数据库服务端配置的超时时间

程序就会在设置的时长之后销毁连接,下次使用就会建立新的连接。

复制代码
//监控程序服务器与数据库服务器的连接情况
    go func() {
        for {
            err := initialize.PingDB()
            if err != nil {
                global.Logger.Error("DB Ping Error", zap.Error(err))
            }
            time.Sleep(30 * time.Second)
        }
    }()
复制代码

补充:

注意:

sql.DB刚开始建立时是懒加载的,不会自动创建新的连接,只有使用Ping()或者运行查询时才会自动生成一个新的连接然后去连接数据库,只有这个时候才能确定数据库是否真的OK,所以建议一定要在sql.Open后运行Ping()确定数据连接正常运行。

sql.DB是连接后初始化的一个连接池,通常全局就初始化这一个连接池,并且长期运行,所有后续数据库操作都使用该连接池进行。sql.DB内部自动维护连接池,当需要连接时自动选择一个空闲的连接,如果没有空闲就建立一个新的连接,当连接不再使用时放回连接池中,内部会自动管理空闲回收。

数据库的连接是一个比较大的耗时和资源消耗操作,首选需要经典的TCP三次握手,tcp连接后数据库需要分配连接资源,同时根据连接信息鉴权等,所以建议使用长连接。对应到我们的go中,sql.DB会自动管理连接池,最好全局使用一个连接池,不要重复的open或者close。

 

posted @   李若盛开  阅读(1566)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示