mysql长连接是指客户端与数据库建立连接后,在较长时间内复用同一个连接进行多次查询。这种方式能减少频繁建立连接带来的开销,但如果连接一直不关闭,mysql服务端为该连接分配的会话级内存(如排序缓冲、临时表空间、预处理语句缓存等)可能不会及时释放,久而久之就会出现内存占用持续增长的现象,也就是常说的长连接内存泄漏。

为什么长连接会导致内存泄漏
mysql为每个连接维护独立的会话内存区。以下因素会加剧内存占用:
- 执行大结果集查询时分配的读缓冲和排序缓冲
- 频繁使用预处理语句导致语句缓存堆积
- 在会话中定义了大量用户变量或临时表
- 连接长时间空闲但服务端仍保留其上下文
虽然mysql在连接关闭时会释放这些资源,但长连接往往数天不关闭,使得内存无法回收。
mysql连接定期重置策略
1. 使用mysql_reset_connection
从mysql 5.7.3开始,C API提供了mysql_reset_connection函数,可以在不关闭连接的情况下重置会话状态,释放大部分会话内存。等效的SQL命令是mysql_reset_connection(注意不是DROP连接)。
-- 在客户端代码中定期执行,重置当前连接会话 mysql_reset_connection; </code>
2. 利用连接池的回收与保活
主流连接池如HikariCP、Druid都支持配置连接最大生命周期,到期后强制丢弃并新建连接,间接实现内存重置。
// HikariCP 配置示例:连接最长存活30分钟
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/test");
config.setMaximumPoolSize(20);
config.setMaxLifetime(30 * 60 * 1000); // 30分钟
HikariDataSource ds = new HikariDataSource(config);
</code>3. 服务端超时参数控制
通过设置wait_timeout和interactive_timeout,让空闲长连接被服务端主动断开。
-- 查看当前超时设置 SHOW VARIABLES LIKE 'wait_timeout'; -- 会话级设置空闲300秒后断开 SET SESSION wait_timeout = 300; </code>
4. 定期执行清理语句
若无法调用重置接口,可定期执行以下语句释放临时资源:
-- 释放表缓存与临时表 FLUSH TABLES; -- 清除用户变量(示例) SET @var1 = NULL; </code>
策略对比
| 策略 | 优点 | 缺点 |
|---|---|---|
| mysql_reset_connection | 轻量,不断连接 | 需要客户端支持 |
| 连接池最大生命周期 | 透明,易配置 | 新建连接略有开销 |
| 服务端超时 | 无需改代码 | 可能误断活跃连接 |
总结建议
在实际生产中,推荐结合连接池的maxLifetime与定期的mysql_reset_connection调用,既避免频繁建连,又防止会话内存累积。同时监控mysql的Threads_connected与内存指标,及时调整策略。