远程MySQL查询时间很长 Druid报skip not validate connection

在将MySQL数据库迁移至云服务器后,服务运行一段时间后出现查询延迟,经分析发现是数据库防火墙自动断开长时间未活动的TCP连接导致。Druid连接池尝试复用已被中断的连接时,会消耗大量时间。解决方案是调整MySQL的net_read_timeout与Druid的timeBetweenEvictionRunsMillis和minEvictableIdleTimeMillis参数,确保两者匹配,以便及时关闭无效连接。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

远程MySQL查询时间很长 Druid报skip not validate connection

情况描述

mysql从本地数据库迁移到云服务器上后,服务启动开始时没有问题,但是运行一段时间后经常遇到查询时间需要十几秒的问题,这个问题困扰了我许久,一直找不到原因。直到一天我看到一篇博文,才得知原因。

报错信息

服务启动后的开始一段时间一般不会有任何问题,但是过了一段时间后,查询时间长达数十秒,一开始我以为是连接池的问题,更换过连接池

一开始使用的是Hikari连接池,这个连接池是SpringBoot默认的,他的错误信息就是说jdbc连接超时异常,然后过一段时间使用其他连接然后查询成功,

这个过程有时长达数十秒。

后来换了druid连接池,还是有同样的问题

druid的一直打印debug级别的日志

Enabling session validation scheduler...
skip not validate connection...
等等

原因分析

从一篇博文中得知别人遇到和我一样的问题,他的原因描述是

数据库服务器的防火墙会自动中断一段时间未活动的TCP连接,相当于中断了数据库物理连接,Druid连接池中维护的数据库逻辑连接尝试与数据库服务器进行被服务器单方面中断的连接进行TCP通信,会失败(Druid把异常捕获了。。只返回false,然后Druid再新开一个TCP连接),重要的是这个失败的过程耗时很长(我们环境反应的是18秒左右的时间)

博文地址: https://www.oschina.net/question/1377217_2135711

但是遗憾的是并没有给出有效的解决方法。

解决方案

后来问了无所不知的群友,我这才得知了三个名词概念

Mysql:net_read_timeout 在终止读之前,从一个连接获得数据而等待的时间秒数;当服务正在从客户端读取数据时,net_read_timeout控制何时超时

druid: timeBetweenEvictionRunsMillis 空闲时间大于这个值时就回判断连接是否还有效

druid: minEvictableIdleTimeMillis 连接空闲时间大于该值并且池中空闲连接大于minIdle则关闭该连接

在这里插入图片描述

Druid的默认timeBetweenEvictionRunsMillis为60s,而我的mysql的net_read_tiemout为30

群里大佬告诉我,read timeout 同 druid 保持一致或者 MySQL 的略长于 druid 的闲置时间,

将timeBetweenEvictionRunsMillis 和minEvictableIdleTimeMillis配置小点

这样就能再连接失效后,关闭失效的连接,避免卡在死连接上。

### 使用 Druid 连接远程 MySQL 数据库的配置方案 在 Java 应用程序中,Druid 是一种高效的数据库连接池工具,能够显著提升应用程序性能并简化数据库连接管理。以下是针对远程 MySQL 数据库的具体配置方法。 #### 1. Maven 依赖引入 为了使用 Druid,需先将其作为依赖项加入项目的 `pom.xml` 文件中: ```xml <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.8</version> <!-- 版本号可根据实际需求调整 --> </dependency> ``` 此部分提供了必要的功能支持来初始化和管理 Druid 连接池[^1]。 #### 2. 初始化 DruidDataSource 实例 通过创建 `DruidDataSource` 类实例完成基本配置设置: ```java import com.alibaba.druid.pool.DruidDataSource; import java.sql.Connection; public class DatabaseConfig { public static void main(String[] args) throws Exception { DruidDataSource druidDataSource = new DruidDataSource(); // 设置基础参数 druidDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); druidDataSource.setUrl("jdbc:mysql://remote_host:3306/database_name?serverTimezone=UTC&useSSL=false"); druidDataSource.setUsername("your_username"); druidDataSource.setPassword("your_password"); // 可选高级配置 (优化性能) druidDataSource.setMaxActive(20); // 最大活跃连接数 druidDataSource.setInitialSize(5); // 初始连接数量 druidDataSource.setMinIdle(5); // 最小闲置连接数 druidDataSource.setMaxWait(60000); // 获取连接的最大等待时间(毫秒) druidDataSource.setTimeBetweenEvictionRunsMillis(60000); druidDataSource.setValidationQuery("SELECT 1"); druidDataSource.setTestWhileIdle(true); try (Connection conn = druidDataSource.getConnection()) { // 测试获取连接 System.out.println("Database connected successfully!"); } catch (Exception e) { e.printStackTrace(); } } } ``` 以上代码片段展示了如何定义数据源以及测试其可用性的过程[^2]。 #### 3. 自动化资源释放机制 为了避免因未及时关闭连接而导致内存泄漏问题,建议采用 `try-with-resources` 或显式调用 `close()` 方法确保所有资源都被妥善处理[^3]: ```java PreparedStatement preparedStatement = null; ResultSet resultSet = null; try ( Connection connection = druidDataSource.getConnection(); PreparedStatement ps = connection.prepareStatement("SELECT * FROM your_table WHERE id=?") ) { ps.setInt(1, 1); // 假设查询条件为 ID 等于 1 resultSet = ps.executeQuery(); while (resultSet.next()) { System.out.println(resultSet.getString("column_name")); } } catch (SQLException ex) { ex.printStackTrace(); } finally { if (preparedStatement != null) { preparedStatement.close(); } if (resultSet != null) { resultSet.close(); } } ``` 这段逻辑不仅实现了 SQL 查询的功能,还保障了异常情况下不会遗漏任何待清理的对象。 #### 4. 密码加密保护措施 出于安全性考虑,在生产环境中推荐对敏感信息如用户名与密码实施加密存储策略。利用 Druid 提供的相关 API 完成此项工作: ```java import com.alibaba.druid.filter.config.ConfigTools; public class PasswordEncryptionExample { public static void main(String[] args) throws Exception { String plainPassword = "original_password"; String encryptedPassword = ConfigTools.encryptPassword(plainPassword); System.out.println("Encrypted password is:" + encryptedPassword); boolean isValid = ConfigTools.validatePassword(plainPassword, encryptedPassword); System.out.println("Is the decrypted password valid?" + isValid); } } ``` 上述示例演示了如何生成密文形式的密码及其验证流程[^4]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值