目 录(本篇字数:859)
介绍
异常情况
原因
解决方法
介绍
最近在调试 Web 应用的时候,由于对数据库的频繁操作(我是获取数据库数据用于显示),导致数据库连接出现了一个异常:Too Many Connections
Too Many Connections 指连接溢出了。我在想明明在代码中将每次获取的 Connection 对象都给释放了,还为什么会出现这个问题呢?后来才发现是由于引入 C3P0 数据库连接池的原因。
异常情况
我以为是这个软件出现了问题,后来使用命令行去获取连接,结果还是连不上。所以,我通过查询当前数据库的最大限制连接数:
> show variables like “max_connections”;
发现连接数是100,估计100不够用,那就再改大一点吧,我改成1000这总可以了吧(在 MySQL 目录下的my.ini文件,修改后记得重启 MySQL 服务)。
然后再去查,发现改过来了。好吧,这下放心去调程序了(这时并未发现是 C3P0 导致的原因)。
。。。经过了一段时间后,又发现 Too Many Connections 异常了。我就纳闷了,这有毒吧,改这么大还不行啊。然后我想看看到底是否真的有这么多连接数,不会是坑我的吧?
> show processlist
列出当前数据库的连接数及详细信息。发现我的连接数全是连到 Person 这个数据库,但是这些连接数全是 Sleep 的状态,而且足足有 1000 个。
原因
随后,我明白了出现这种问题的原因是我的代码出现了问题,因为我引入了 C3P0 连接池,所以每次创建连接池的时候,我都会想数据库申请初始化的连接数大小:30个
这不是问题的关键,关键的是我每次调用 getConnection() 方法都会 new 一个 ComboPooledDataSource(“c3p0-configs”) 的数据源对象。所以连接数会按照 30 的倍数增长,最终导致连接溢出。
C3P0 连接池有一个特点,它并不会主动摧毁连接,即使调用 close() 方法,最终没有使用的会以 “Sleep” 的状态存在连接池当中。
解决方法
既然我们找到了原因, 解决方法很简单。
- 每次都把new的dataSource 对象释放(不可取,相当于每次使用时又创建一个池,这样就失去池的意义)
- 把连接设置为单例类(推荐)
将我的 JDBCUtils 工具类改为一个单利,就不会出现 Too Many Connections 的情况了。
package com.xww.utils;
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class JDBCUtils {
private DataSource dataSource = null;
public static class Holder {
private static JDBCUtils instance = new JDBCUtils();
}
public static JDBCUtils getIns() {
return Holder.instance;
}
public JDBCUtils() {
dataSource = new ComboPooledDataSource("c3p0-configs");
}
public Connection getConnection() {
Connection conn = null;
try {
conn = dataSource.getConnection();
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
public static void release(Connection conn) {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
@作者博客:_Xu2WeI