前段时间,接手一个项目使用的是原始的jdbc作为数据库的访问,发布到服务器上在运行了一段时间之后总是会出现无法访问的情况,登录到服务器,查看tomcat日志发现总是报如下的错误。

  

Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Data source rejected establishment of connection,  message from server: "Too many connections"
at sun.reflect.GeneratedConstructorAccessor43.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
at com.mysql.jdbc.Util.handleNewInstance(Util.java:406)
at com.mysql.jdbc.Util.getInstance(Util.java:381)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:984)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:956)
at com.mysql.jdbc.MysqlIO.doHandshake(MysqlIO.java:1095)
at com.mysql.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:2181)
... 32 more
com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Could not create connection to database server. Attempted reconnect 3 times. Giving up.

  

Data source rejected establishment of connection,  message from server: "Too many connections"
通过对这句话的分析可以得知,是因为数据库的连接太多了,数据库连接被拒绝了,导致了项目的无法访问。
于是先查看MySql最大连接数
show variables like "max_connections";

 显示当前正在执行的MySql连接

show processlist ;

 通过这两个数据的对比,发现MySql的连接数居然满了,于是修改了MySql的最大连接数至2000,重启项目之后发现一切正常,过了一段时间之后,继续查询MySql的连接状态,发现MySql的连接数不停的在飙升,不一会的功夫连接数又满了,这时候,我开始意识到是项目的代码出现了问题,于是我开始审查代码,发现项目中使用的JdbcUtils工具类并不是单例模式,在每次使用JdbcUtils的时候都会new一个JdbcUtils对象,在创建对象的时候会使用java.sql.Connection建立连接,但是在使用完JdbcUtils的时候,我们并没有调用Connection的close()方法,这样导致使用jdbc连接数据库的时候会导致连接数越来越多,然而没用的连接数却没有释放掉,最终到时数据库连接报错,项目无法使用数据库了。

  于是我觉得使用数据库连接池来整合jdbc,连接池的介绍如下:

  对于共享资源,有一个很著名的设计模式:资源池(Resource Pool)。该模式正是为了解决资源的频繁分配﹑释放所造成的问题。为解决我们的问题,可以采用数据库连接池技术。数据库连接池的基本思想就是为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去。我们可以通过设定连接池最大连接数来防止系统无尽的与数据库连接。更为重要的是我们可以通过连接池的管理机制监视数据库的连接的数量﹑使用情况,为系统开发﹑测试及性能调整提供依据。

  

传统的获取连接方式如下图所示:

用户每次请求都需要向数据库获得链接,而数据库创建连接通常需要消耗相对较大的资源,创建时间也较长。假设网站一天10万访问量,数据库服务器就需要创建10万次连接,极大的浪费数据库的资源,并且极易造成数据库服务器内存溢出、拓机。

采用连接池技术后的过程如下:

数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现的尤为突出。对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标。数据库连接池负责分配,管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个。

C3P0连接池

c3p0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。c3p0一般是与Hibernate,Spring等框架一块使用的,当然也可以单独使用。

dbcp没有自动回收空闲连接的功能,c3p0有自动回收空闲连接功能

使用c3p0需要导入c3p0.jarmchange-commons-.jar,如果操作的是Oracle数据库,那么还需要导入c3p0-oracle-thin-extras-pre1.jar。

下面开始使用C3P0整合JDBC

数据库配置:

#Oracle Config
#jdbc.driver=oracle.jdbc.driver.OracleDriver
#jdbc.url=jdbc:oracle:thin:@localhost:1521:ora9i
#jdbc.username=qq
#jdbc.pwd=qq #MySQL Config
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.username=jdbctest
jdbc.pwd=123456

DBUtils,初始化连接池配置,设置数据库的最大连接数和最小连接数

package hn.veryedu.jdbc.common.db;

import java.io.FileInputStream;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties; import javax.sql.DataSource; import com.mchange.v2.c3p0.DataSources; public class DBUtils { private static String url = null; private static String username = null; private static String pwd = null; private static DataSource ds_pooled;
/**
* 加载数据库连接的配置文件和驱动
*/
static{
FileInputStream fis = null; Properties env = new Properties();
try {
fis = new FileInputStream("dbconfig.properties");
//加载属性文件中的数据库配置信息
//以=左边作为key值,右边作为value值
env.load(fis); //1. 加载驱动类
Class.forName(env.getProperty("jdbc.driver")); url = env.getProperty("jdbc.url");
username = env.getProperty("jdbc.username");
pwd = env.getProperty("jdbc.pwd"); //设置连接数据库的配置信息
DataSource ds_unpooled = DataSources
.unpooledDataSource(url, username, pwd); Map<String, Object> pool_conf = new HashMap<String, Object>();
//设置最大连接数
pool_conf.put("maxPoolSize", 20);
//连接池应该保有的最小连接的数量
pool_conf.put("minPoolSize", 2);
//初始化连接池时,获取的连接个数
pool_conf.put("initialPoolSize", 10);
//当连接池中已经没有连接时,连接池自动获取连接时一次获取的连接个数
pool_conf.put("acquireIncrement", 3);
ds_pooled = DataSources.pooledDataSource(ds_unpooled,
pool_conf);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
} /**
* 获取连接对象
*/
public static Connection getConnection() {
// 2. 设置连接的url,username,pwd
Connection connection = null;
try {
connection = ds_pooled.getConnection();
//connection.prepareStatement("set names utf8mb4").executeQuery();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return connection;
} /**
* 释放连接池资源
*/
public static void clearup(){
if(ds_pooled != null){
try {
DataSources.destroy(ds_pooled);
} catch (SQLException e) {
e.printStackTrace();
}
}
} /**
* 资源关闭
*
* @param rs
* @param stmt
* @param conn
*/
public static void close(ResultSet rs, Statement stmt
, Connection conn) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
} if (stmt != null) {
try {
stmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
} if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}

然后是JdbcUtils查询各种数据List、Map等,通过DBUtils获取数据库连接,使用完成之后释放所有的连接

package hn.veryedu.jdbc.common.db;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map; public class JdbcUtils {
private Connection connection;
private PreparedStatement pstmt;
private ResultSet resultSet; /**
* 获得数据库的连接
* @return
* @throws SQLException
*/
public Connection getConnection() throws SQLException{
connection = DBUtils.getConnection();
//如果数据库支持utf8mb4 建立连接后需要使用下面的代码
//connection.prepareStatement("set names utf8mb4").executeQuery();
return connection;
} /**
* 增加、删除、改
* @param sql
* @param params
* @return
* @throws SQLException
*/
public boolean updateByPreparedStatement(String sql, List<Object> params)throws SQLException{
boolean flag = false;
int result = -1;
this.getConnection();
pstmt = connection.prepareStatement(sql);
int index = 1;
if(params != null && !params.isEmpty()){
for(int i=0; i<params.size(); i++){
pstmt.setObject(index++, params.get(i));
}
}
result = pstmt.executeUpdate();
flag = result > 0 ? true : false;
this.releaseConn();
return flag;
} /**
* 查询单条记录
* @param sql
* @param params
* @return
* @throws SQLException
*/
public Map<String, Object> findSimpleResult(String sql, List<Object> params) throws SQLException{
Map<String, Object> map = new HashMap<String, Object>();
int index = 1;
this.getConnection();
pstmt = connection.prepareStatement(sql);
if(params != null && !params.isEmpty()){
for(int i=0; i<params.size(); i++){
pstmt.setObject(index++, params.get(i));
}
}
resultSet = pstmt.executeQuery();//返回查询结果
ResultSetMetaData metaData = resultSet.getMetaData();
int col_len = metaData.getColumnCount();
while(resultSet.next()){
for(int i=0; i<col_len; i++ ){
String cols_name = metaData.getColumnName(i+1);
Object cols_value = resultSet.getObject(cols_name);
if(cols_value == null){
cols_value = "";
}
map.put(cols_name, cols_value);
}
}
this.releaseConn();
return map;
} /**
* 查询多条记录
* @param sql
* @param params
* @return
* @throws SQLException
*/
public List<Map<String, Object>> findModeResult(String sql, List<Object> params) throws SQLException{
List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
int index = 1;
this.getConnection();
pstmt = connection.prepareStatement(sql);
if(params != null && !params.isEmpty()){
for(int i = 0; i<params.size(); i++){
pstmt.setObject(index++, params.get(i));
}
}
resultSet = pstmt.executeQuery();
ResultSetMetaData metaData = resultSet.getMetaData();
int cols_len = metaData.getColumnCount();
while(resultSet.next()){
Map<String, Object> map = new HashMap<String, Object>();
for(int i=0; i<cols_len; i++){
String cols_name = metaData.getColumnName(i+1);
Object cols_value = resultSet.getObject(cols_name);
if(cols_value == null){
cols_value = "";
}
map.put(cols_name, cols_value);
}
list.add(map);
}
this.releaseConn();
return list;
} /**
* 通过反射机制查询单条记录
* @param sql
* @param params
* @param cls
* @return
* @throws Exception
*/
public <T> T findSimpleRefResult(String sql, List<Object> params,
Class<T> cls )throws Exception{
T resultObject = null;
int index = 1;
this.getConnection();
pstmt = connection.prepareStatement(sql);
if(params != null && !params.isEmpty()){
for(int i = 0; i<params.size(); i++){
pstmt.setObject(index++, params.get(i));
}
}
resultSet = pstmt.executeQuery();
ResultSetMetaData metaData = resultSet.getMetaData();
int cols_len = metaData.getColumnCount();
while(resultSet.next()){
//通过反射机制创建一个实例
resultObject = cls.newInstance();
for(int i = 0; i<cols_len; i++){
String cols_name = metaData.getColumnName(i+1);
Object cols_value = resultSet.getObject(cols_name);
if(cols_value == null){
cols_value = "";
}
Field field = cls.getDeclaredField(cols_name);
field.setAccessible(true); //打开javabean的访问权限
field.set(resultObject, cols_value);
}
}
this.releaseConn();
return resultObject;
} /**
* 通过反射机制查询多条记录
* @param sql
* @param params
* @param cls
* @return
* @throws Exception
*/
public <T> List<T> findMoreRefResult(String sql, List<Object> params,
Class<T> cls )throws Exception {
List<T> list = new ArrayList<T>();
int index = 1;
this.getConnection();
pstmt = connection.prepareStatement(sql);
if(params != null && !params.isEmpty()){
for(int i = 0; i<params.size(); i++){
pstmt.setObject(index++, params.get(i));
}
}
resultSet = pstmt.executeQuery();
ResultSetMetaData metaData = resultSet.getMetaData();
int cols_len = metaData.getColumnCount();
while(resultSet.next()){
//通过反射机制创建一个实例
T resultObject = cls.newInstance();
for(int i = 0; i<cols_len; i++){
String cols_name = metaData.getColumnName(i+1);
Object cols_value = resultSet.getObject(cols_name);
if(cols_value == null){
cols_value = "";
}
Field field = cls.getDeclaredField(cols_name);
field.setAccessible(true); //打开javabean的访问权限
field.set(resultObject, cols_value);
}
list.add(resultObject);
}
this.releaseConn();
return list;
} /**
* 返回单个结果值,如count\min\max等
*
* @param sql
* sql语句
* @param paramters
* 参数列表
* @return 结果
* @throws SQLException
*/
public Integer queryForInt(String sql, Object... paramters)
throws SQLException {
Integer result = null; try {
this.getConnection();
pstmt = connection.prepareStatement(sql); for (int i = 0; i < paramters.length; i++) {
pstmt.setObject(i + 1, paramters[i]);
}
resultSet = pstmt.executeQuery(); ResultSetMetaData metaData = resultSet.getMetaData();
while(resultSet.next()){
String cols_name = metaData.getColumnName(0+1);
Object cols_value = resultSet.getObject(cols_name);
result = Integer.valueOf(cols_value.toString());
}
return result;
} catch (SQLException e) {
throw new SQLException(e);
} finally {
releaseConn();
}
} /**
* 释放数据库连接
*/
public void releaseConn(){
DBUtils.close(resultSet, pstmt, connection);
} }

测试类TestMySQLConnection

package hn.veryedu.jdbc.mysql;

import hn.veryedu.jdbc.common.db.DBUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException; public class TestMySQLConnection {
private static Integer counter = 0; public static void main(String[] args){ for (int i = 1; i <= 2000; i++) {
new Thread(new Runnable() {
public void run() {
Connection conn = null;
PreparedStatement pstmt= null;
ResultSet resultSet= null;
try {
conn = DBUtils.getConnection();
synchronized (counter) {
System.out.print(Thread.currentThread().getName());
System.out.print(" counter = " + counter++
+ " conn = " + conn);
System.out.println(); pstmt = conn.prepareStatement("select * from user_t");
resultSet = pstmt.executeQuery();
ResultSetMetaData metaData = resultSet.getMetaData();
int cols_len = metaData.getColumnCount();
while(resultSet.next()){
for(int i=0; i<cols_len; i++){
String cols_name = metaData.getColumnName(i+1);
Object cols_value = resultSet.getObject(cols_name);
//System.out.println(cols_name+"---"+cols_value);
}
}
DBUtils.close(resultSet, pstmt, conn);
//conn.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}).start();
}
}
}

测试类TestJdcb

package hn.veryedu.jdbc.mysql;

import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import hn.veryedu.jdbc.common.db.JdbcUtils; public class TestJdcb { /**
* @param args
* @throws SQLException
*/
public static void main(String[] args) throws SQLException {
// TODO Auto-generated method stub
for (int i = 1; i <= 20; i++){
JdbcUtils jdbc = new JdbcUtils();
String sql = "select * from user_t";
List<Map<String, Object>> list = jdbc.findModeResult(sql, null);
for (int j = 0; j < list.size(); j++) {
System.out.println(list.get(j));
}
}
} }

通过这两个测试进行数据库访问的测试,发现无论运行多少次,数据库当前的连接数都是不变的,这样就再也不用担心数据库的连接数会满啦!

前段时间,接手一个项目使用的是原始的jdbc作为数据库的访问,发布到服务器上在运行了一段时间之后总是会出现无法访问的情况,登录到服务器,查看tomcat日志发现总是报如下的错误。    Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Data source rejected est的更多相关文章

  1. 由于没有发现潜在的递归导致MySQL链接数溢出:MySQLNonTransientConnectionException: Data source rejected establishment of connection, message from server: "Too many connec

    DAOProxy的代码:下面代码中红色高亮的就是出问题的地方,DAOFactory中会构造一个PersonDAOProxy,调用listPersons或者addPerson显然会导致递归,从而导致My ...

  2. Linux 实时查看tomcat 日志--less命令

    查看tomcat日志通常用 tail -n  或者 tail -f 或者grep 或者 vi cat等命令去查看异常信息,但是日志是在不停地刷屏,tail是动态的在变的,我们往往期望从日志最后一行往前 ...

  3. SSH项目过一段时间之后再访问会报一次Could not open Hibernate session for transaction 异常,Caused by: com.mysql.jdbc.CommunicationsException: Communications link failure due to underlyi,再重新方法即可访问成功(通常出现在过了一晚之后再去访问系统)

    前端时间到客户那去进行项目的上线测试,将项目部署好之后,运行都是正常的,可是每到了第二天早上访问的时候,就会报一个Could not open Hibernate session for transa ...

  4. java项目连接jdbc报错:com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Could not create connection to database server

    java项目连接jdbc报错:com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Could not creat ...

  5. linux查看tomcat日志

    声明:以上内容均为转载,个人对这块知识搜罗之后放在一起,非原创,以后这块有问题还会继续添加. Tomcat 日志分为下面5类: catalina . 相当命令行输出日志 localhost . 相当于 ...

  6. 如何运用Linux进行查看tomcat日志

    第一步:进入tomcat目录下的logs.cd home /tomcat/logs 第二步:运行并查看日志:tail -f catalina.out 第三步:想终止查看:ctrl +c退出 第四步:比 ...

  7. linux系统部署war包,查看tomcat日志

    1.部署war包app/tomcat/bin在tomcat/bin 目录下启动 .startup.sh,在启动过程中tomcat会对war包进行解压,形成相应的项目目录 执行命令:./startup. ...

  8. linux 查看tomcat 日志

    tomcat 重启: cd /opt/appserver/apache-tomcat-/bin ./shutdown.sh -ef|grep tomcat kill - ./startup.sh 查看 ...

  9. 【linux】linux上 查看tomcat日志文件

    1.查看实时日志文件 tail -f catalina.out 2.实时查看日志文件 最后n行 tail -n -f catalina.out 3.退出tail命令 ctrl + C 4.翻页查看 日 ...

随机推荐

  1. async与await 实例

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  2. elasticsearch简介和倒排序索引介绍

    介绍 我们为什么要用搜索引擎?我们的所有数据在数据库里面都有,而且 Oracle.SQL Server 等数据库里也能提供查询检索或者聚类分析功能,直接通过数据库查询不就可以了吗?确实,我们大部分的查 ...

  3. 菜鸟学Java(八)——dom4j详解之读取XML文件

    dom4j是一个Java的XML API,类似于jdom,用来读写XML文件的.dom4j是一个非常非常优秀的Java XML API,具有性能优异.功能强大和极端易用使用的特点,同时它也是一个开放源 ...

  4. C++中的友元函数和友元类

    C++中的友元函数主要应用于以下场景: 友元函数 第一种场景 代码中有一个全局函数,该函数想要去访问某个类的成员变量(该类的成员变量是private的,且该类并未提供任何获取获取私有成员变量的publ ...

  5. JAVA线程池任务数大小设置

    线程池究竟设成多大是要看你给线程池处理什么样的任务,任务类型不同,线程池大小的设置方式也是不同的. 任务一般可分为:CPU密集型.IO密集型.混合型,对于不同类型的任务需要分配不同大小的线程池. CP ...

  6. Java中创建String的两种方式差异

    我们知道创建一个String类型的变量一般有以下两种方法: String str1 = "abcd"; String str2 = new String("abcd&qu ...

  7. 关于RPG游戏结构撰写的相关探索上篇

    本章节的目标是创造一个游戏理念.这个理念是: *简短的项目概括 *范围描述 *目标用户 *与其他游戏的区别 不要试图编写一款缺乏明确理念的RPG.因为这样可能只会产生与其他游戏雷同的项目. <i ...

  8. ImportError: cannot import name 'main'的解决办法

    一.现象 使用pip出现如下提示: Traceback (most recent call last): File "/usr/bin/pip3", line 9, in < ...

  9. 【Java】PreparedStatement VS Statement

    创建时: Statement statement = conn.createStatement();    PreparedStatement preStatement = conn.prepareS ...

  10. iOS中大文件下载(单线程下载)

    主要是需要注意,在客服端发请求给服务器的时候,在请求头里是可以设置服务器返回的数据从哪开始,到哪结束的. 当服务器响应客户端时,是可以拿到服务器返回数据具体类型以及大小的 思路: 在接收到服务器响应时 ...