场景

使用 alibaba druid 访问 mysql,执行一段时间后报错:

The last packet successfully received from the server was XXX milliseconds ago

原因

MySQL连接已经超时了,即长时间没有收到新的查询请求。连接处于空闲状态而被MySQL服务器关闭。

解决方式

你可以尝试使用以下方法来解决这个问题:

  1. 检查数据库服务器和应用服务器之间的网络连接是否正常,特别是在高延迟或不稳定的网络环境下。

  2. 增加数据库连接的超时时间,这可以通过在JDBC URL中添加”autoReconnect=true&autoReconnectForPools=true&connectTimeout=30000&socketTimeout=60000”参数实现(具体数值可以根据实际情况调整)。

  3. 使用 数据库连接池来管理连接,可以更好地控制连接的超时时间和重连逻辑。

  4. 检查数据库是否已满,如果数据库已经使用了大量的系统资源,那么此时数据库的性能可能很低,以至于无法响应新的查询请求。

实战笔记

查询超时时间

mysql> show variables like '%timeout%';
+-----------------------------+----------+
| Variable_name               | Value    |
+-----------------------------+----------+
| connect_timeout             | 10       |
| delayed_insert_timeout      | 300      |
| have_statement_timeout      | YES      |
| innodb_flush_log_at_timeout | 1        |
| innodb_lock_wait_timeout    | 50       |
| innodb_rollback_on_timeout  | OFF      |
| interactive_timeout         | 28800    |
| lock_wait_timeout           | 31536000 |
| net_read_timeout            | 30       |
| net_write_timeout           | 60       |
| rpl_stop_slave_timeout      | 31536000 |
| slave_net_timeout           | 60       |
| wait_timeout                | 28800    |
+-----------------------------+----------+

属性解释如下:

当然,以下是以表格形式返回的 MySQL 超时相关变量及其解释:

Variable_name Value 解释
connect_timeout 10 服务器等待客户端连接的时间(秒)。默认10秒。
delayed_insert_timeout 300 INSERT DELAYED 插入数据的等待时间(秒)。默认300秒。
have_statement_timeout YES 指示是否支持 SQL 语句的超时设置。默认支持。
innodb_flush_log_at_timeout 1 InnoDB 日志缓冲区的刷新间隔时间(秒)。默认1秒。
innodb_lock_wait_timeout 50 InnoDB 事务等待锁释放的时间(秒)。默认50秒。
innodb_rollback_on_timeout OFF 事务超时时是否回滚整个事务。默认不回滚。
interactive_timeout 28800 交互式客户端空闲超时时间(秒)。默认28800秒。
lock_wait_timeout 31536000 锁等待超时时间(秒)。默认31536000秒。
net_read_timeout 30 服务器等待从客户端读取数据的时间(秒)。默认30秒。
net_write_timeout 60 服务器等待向客户端写入数据的时间(秒)。默认60秒。
rpl_stop_slave_timeout 31536000 复制停止从服务器的超时时间(秒)。默认31536000秒。
slave_net_timeout 60 从服务器等待主服务器数据的时间(秒)。默认60秒。
wait_timeout 28800 非交互式客户端空闲超时时间(秒)。默认28800秒。

修改配置

我们可以修改 mysql 的配置文件 my.cnf(/etc/my.cnf 文件所在位置)

wait_timeout=1200000
interactive_timeout=1200000

重启 mysql 服务在次执行 show variables like ‘%timeout%’; 命令查看wait_timeout连接等待时间

jdbc url 调整

连接mysql url添加参数

&keepAlive=true&autoReconnect=true&autoReconnectForPools=true&connectTimeout=30000&socketTimeout=60000

解释:

属性名 解释
keepAlive true 启用 TCP keep-alive 功能,以检测和保持连接的活跃状态。
autoReconnect true 启用自动重新连接功能,当连接失效时,自动重新建立连接。
autoReconnectForPools true 启用自动重新连接功能,专用于连接池中的连接自动恢复。
connectTimeout 30000 指定连接超时时间(以毫秒为单位),默认30,000毫秒(30秒)。
socketTimeout 60000 指定套接字读写操作的超时时间(以毫秒为单位),默认60,000毫秒(60秒)。

druid 推荐的配置

例子

{
	"initial-size": 10,
	"min-idle": 5,
	"maxActive": 30,
	"timeBetweenEvictionRunsMillis": 50000,
	"validationQuery": "SELECT 1",
	"testWhileIdle": true,
	"test-on-borrow": false,
	"test-on-return": false,
	"test-while-idle": false,
	"min-evictable-idle-time-millis": 300000,
	"max-evictable-idle-time-millis": 600000
}

解释:

属性名 解释
initial-size 10 初始化时建立的连接数。
min-idle 5 连接池中最小空闲连接数。
maxActive 30 连接池中最大活动连接数。
timeBetweenEvictionRunsMillis 50000 两次空闲连接回收器运行之间的时间间隔(以毫秒为单位)。
validationQuery SELECT 1 用于检测连接是否有效的 SQL 查询语句。
testWhileIdle true 指定空闲连接是否需要经过验证。
test-on-borrow false 指定从连接池借用连接时是否需要经过验证。
test-on-return false 指定从连接池归还连接时是否需要经过验证。
test-while-idle false (重复属性)指定空闲连接是否需要经过验证。
min-evictable-idle-time-millis 300000 连接在池中保持空闲而不被驱逐的最小时间(以毫秒为单位)。
max-evictable-idle-time-millis 600000 连接在池中保持空闲而不被驱逐的最大时间(以毫秒为单位)。

这里要保证 max-evictable-idle-time-millis 小于 mysql 设置的最大等待时间。

testWhileIdle=true,timeBetweenEvictionRunsMillis=60s 左右,定期检测连接的有效性。

经过上面的几步,问题解决。

参考资料

mysql 超时

https://blog.csdn.net/weixin_43103956/article/details/136389845

https://blog.csdn.net/JGMa_TiMo/article/details/130404972