目    录(本篇字数:859)

介绍

异常情况

原因

解决方法


介绍

    最近在调试 Web 应用的时候,由于对数据库的频繁操作(我是获取数据库数据用于显示),导致数据库连接出现了一个异常:Too Many Connections

    Too Many Connections 指连接溢出了。我在想明明在代码中将每次获取的 Connection 对象都给释放了,还为什么会出现这个问题呢?后来才发现是由于引入 C3P0 数据库连接池的原因。

异常情况

数据库报错 out of memory 数据库报too many connections_连接数

    我以为是这个软件出现了问题,后来使用命令行去获取连接,结果还是连不上。所以,我通过查询当前数据库的最大限制连接数:

show variables like “max_connections”;

数据库报错 out of memory 数据库报too many connections_连接数_02

    发现连接数是100,估计100不够用,那就再改大一点吧,我改成1000这总可以了吧(在 MySQL 目录下的my.ini文件,修改后记得重启 MySQL 服务)。

数据库报错 out of memory 数据库报too many connections_数据库_03

数据库报错 out of memory 数据库报too many connections_数据库报错 out of memory_04

   

    然后再去查,发现改过来了。好吧,这下放心去调程序了(这时并未发现是 C3P0 导致的原因)。

    。。。经过了一段时间后,又发现 Too Many Connections 异常了。我就纳闷了,这有毒吧,改这么大还不行啊。然后我想看看到底是否真的有这么多连接数,不会是坑我的吧?

> show processlist

    列出当前数据库的连接数及详细信息。发现我的连接数全是连到 Person 这个数据库,但是这些连接数全是 Sleep 的状态,而且足足有 1000 个。

数据库报错 out of memory 数据库报too many connections_连接数_05

原因

    随后,我明白了出现这种问题的原因是我的代码出现了问题,因为我引入了 C3P0 连接池,所以每次创建连接池的时候,我都会想数据库申请初始化的连接数大小:30个

数据库报错 out of memory 数据库报too many connections_数据库_06

    这不是问题的关键,关键的是我每次调用 getConnection() 方法都会 new 一个 ComboPooledDataSource(“c3p0-configs”) 的数据源对象。所以连接数会按照 30 的倍数增长,最终导致连接溢出。

    C3P0 连接池有一个特点,它并不会主动摧毁连接,即使调用 close() 方法,最终没有使用的会以 “Sleep” 的状态存在连接池当中。

数据库报错 out of memory 数据库报too many connections_数据库报错 out of memory_07

解决方法

   既然我们找到了原因, 解决方法很简单。

  1. 每次都把new的dataSource 对象释放(不可取,相当于每次使用时又创建一个池,这样就失去池的意义)
  2. 把连接设置为单例类(推荐)

    将我的 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