参考: Mysql连接无效(invalid connection)解决方案_dghpgyss的博客-CSDN博客 mysql经典的8小时问题-wait_timeout - 简书 golang mysql unexpected EOF(invalid connection) - 翔云123456 - 博客园
首先来看看?“wait_timeout” 这个参数设置,如图:
?报错截图:
问题产生原因:?
Mysql服务器默认的 “wait_timeout” 是8小时【28800秒】,也就是一个连接在8小时内没有活动,就会自动断开该连接。所以由于部分连接长时间空闲,一些实现版本中的连接池中以为被断开的连接仍然有效,其实拿到的连接是已经无效的连接(invalid connection)。在这种情况下,客户端向该连接池请求连接时,会导致MySQL查询异常。
为啥白天用户多的时候不会发生这个问题呢?
答:在高峰时期用户很多,每个连接在达到 超时时间?之前就被复用了,然后连接的超时时间就会重置,所以用户多的时候并不容易出现这个问题。
请根据业务场景,来配置 wait_timeout 等参数...
解决方法:
临时解决方法:重启服务建立新的MySQL连接对象、或者mysql配置参数 “wait_timeout” 调久一些,避免被自动断开 根本解决方法:将go-mysql-driver从1.4升级到?Version?1.5?(2020-01-07),当遇到无效的连接时,会自动重新连接池中的无效连接。(有待验证~)
一般连接数据库的代码库都有实现连接池,如golang语言的database/sql库。其中SetConnMaxLifetime(d time.Duration)?是用来设置连接池中的 “每条连接最长存活期”,其参数d:
- 当d <= 0时,连接池里的连接永久重用,即永远都在连接池里,拿来就用,不管此连接是否真的有效(这里有问题,下面讲)。
- 当d > 0时,到了时间d才会关闭连接,把连接移出连接池,但这并不是时间一到就关闭,因为当连接还在使用时会等连接完成之后,等下一个清理连接周期(周期为d)时会关闭连接,移出连接
package main
import (
_ "github.com/go-sql-driver/mysql"
"github.com/jmoiron/sqlx"
)
func main() {
dns := fmt.Sprintf("%s:%s@tcp(%s)/%s", "user", "password", "ip:port", "database")
db, err := sqlx.Open("mysql", dns)
if err != nil {
log.Fatalf("newDb db init error, error:%v", err)
}
db.SetMaxIdleConns(10) // 最大空闲连接数(默认值2)
db.SetMaxOpenConns(50) // 数据库最大连接数(默认值0,无限制)
db.SetConnMaxLifetime(3595 * time.Second) // 连接最长存活期,超过这个时间连接将不再被复用(默认值0,永不过期)
return
}
|