MySQL 连接池内的invalid connection

参考:

首先来看看 “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
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值