Apache DBCP数据库连接池溢出调整

数据库最大连接池溢出是在系统运行中比较常见的一个问题,在开发中,可以通过设置最大连接池的各位为1或者2,就能在开发的时候发现数据库连接没有被释放的情况。不过这个小技巧在hibernate和sping等框架大量使用之后就没什么用了。

数据库连接池溢出的源代码:

package test.ffm83.commons.dbcp;

import org.apache.commons.dbcp.BasicDataSource;

import org.apache.commons.dbcp.BasicDataSourceFactory;

import org.apache.commons.lang.StringUtils;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.sql.SQLException;

import java.sql.Connection;

import java.util.Properties;

/* 通过dbcp连接oracle数据库,模拟连接池溢出

* 使用1.4版本实现

* @author 范芳铭

* */

public
class
DbcpUsageParamA {

private
static
BasicDataSource dataSource =
null;

public DbcpUsageParamA() {

}

public
static void
init() {

if (dataSource !=
null) {

try {

dataSource.close();

}catch(Exception e) {

e.printStackTrace();

}

dataSource =
null;

}

try {

Propertiesp = newProperties();

p.setProperty("driverClassName","oracle.jdbc.driver.OracleDriver");

p.setProperty("url",
"jdbc:oracle:thin:@192.168.19.24:1521:fanfangming");

p.setProperty("password","ffm");

p.setProperty("username","ffm");

p.setProperty("maxActive","2");
//最大连接数

p.setProperty("maxIdle","1");

p.setProperty("maxWait","10");

dataSource =(BasicDataSource) BasicDataSourceFactory

.createDataSource(p);

}catch(Exception e) {

e.printStackTrace();

}

}

public
static synchronized
ConnectiongetConnection()
throwsSQLException {

if (dataSource ==
null) {

init();

}

Connectionconn = null;

if (dataSource !=
null) {

conn= dataSource.getConnection();

}

return conn;

}

public
static void
main(String[] args)
throws Exception {

getConAndNotClose();

getConAndNotClose();

getConAndNotClose();

}

//本方法使用数据库连接但是不释放,用来模拟连接池溢出情况

private
static void
getConAndNotClose()
throws Exception{

Connectioncon = null;

try {

con= DbcpUsageParamA.getConnection();

Stringsql = " select sysdate from dual ";

PreparedStatementps = con.prepareStatement(sql);

ResultSetrs = ps.executeQuery();

while (rs.next()) {

Stringvalue = rs.getString("sysdate");

System.out.println(StringUtils.center(value+",数据库连接成功", 50,
"-"));

}

}catch(Exception e) {

e.printStackTrace();

}

//注意,这里没有关闭数据库连接池,实际代码不要这么写。

}

}

运行结果:

----------2014-12-16 12:47:49.0,数据库连接成功-----------

----------2014-12-16 12:47:49.0,数据库连接成功-----------

org.apache.commons.dbcp.SQLNestedException: Cannot get a connection, pool error Timeout waiting for idle object

atorg.apache.commons.dbcp.PoolingDataSource.getConnection(PoolingDataSource.java:114)

….

其他几个参数也可以这样去测试。

在配置时,主要难以理解的主要有:removeAbandoned 、logAbandoned、removeAbandonedTimeout、maxWait这四个参数,设置了rmoveAbandoned=true那么在getNumActive()快要到getMaxActive()的时候,系统会进行无效的Connection的回收,回收的Connection为removeAbandonedTimeout(默认300秒)中设置的秒数后没有使用的Connection。

如果开启"removeAbandoned",那么连接在被认为泄露时可能被池回收. 这个机制在(getNumIdle() < 2) and (getNumActive()> getMaxActive() - 3)时被触发.

举例当maxActive=20,活动连接为18,空闲连接为1时可以触发"removeAbandoned".

看了这么多,先看一个例子,关于removeAbandoned。

package test.ffm83.commons.dbcp;

import org.apache.commons.dbcp.BasicDataSource;

importorg.apache.commons.dbcp.BasicDataSourceFactory;

import org.apache.commons.lang.StringUtils;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.sql.SQLException;

import java.sql.Connection;

import java.util.Properties;

/* 通过dbcp连接oracle数据库,体验连不释放下的removeAbandoned等参数

* 使用1.4版本实现

* @author 范芳铭

* */

public class DbcpAbandone {

privatestatic BasicDataSource dataSource = null;

publicDbcpAbandone() {

}

publicstatic void init() {

if(dataSource != null) {

try{

dataSource.close();

}catch (Exception e) {

e.printStackTrace();

}

dataSource= null;

}

try{

Propertiesp = new Properties();

p.setProperty("driverClassName","oracle.jdbc.driver.OracleDriver");

p.setProperty("url","jdbc:oracle:thin:@192.168.1.1:1521:fanfangming");

p.setProperty("password","ffm");

p.setProperty("username","ffm");

p.setProperty("maxActive","6"); //

p.setProperty("maxIdle","3");

p.setProperty("maxWait","10");

p.setProperty("removeAbandoned","true");//移除不用的连接

p.setProperty("removeAbandonedTimeout","8");

p.setProperty("logAbandoned","true");

dataSource= (BasicDataSource) BasicDataSourceFactory

.createDataSource(p);

}catch (Exception e) {

e.printStackTrace();

}

}

publicstatic synchronized Connection getConnection() throws SQLException {

if(dataSource == null) {

init();

}

Connectionconn = null;

if(dataSource != null) {

conn= dataSource.getConnection();

}

returnconn;

}

publicstatic void main(String[] args) throws Exception {

for(inti=0;i < 10 ; i++){

getConAndNotClose(i+1);

}

}

//本方法使用数据库连接但是不释放,用来模拟连接池溢出情况

privatestatic void getConAndNotClose(int id) throws Exception{

Connectioncon = null;

try{

con= DbcpAbandone.getConnection();

Stringsql = " select sysdate from dual ";

PreparedStatementps = con.prepareStatement(sql);

ResultSetrs = ps.executeQuery();

while(rs.next()) {

Stringvalue = rs.getString("sysdate");

Thread.sleep(6* 1000);

System.out.println(StringUtils.center(value+","+id+"数据库连接成功", 50, "-"));

}

}catch (Exception e) {

e.printStackTrace();

}

//注意,这里没有关闭数据库连接池,实际代码不要这么写。

}

}

运行结果如下:

----------2014-12-16 14:12:45.0,1数据库连接成功----------

----------2014-12-16 14:12:53.0,2数据库连接成功----------

----------2014-12-16 14:13:00.0,3数据库连接成功----------

----------2014-12-16 14:13:06.0,4数据库连接成功----------

----------2014-12-16 14:13:13.0,5数据库连接成功----------

----------2014-12-16 14:13:20.0,6数据库连接成功----------

----------2014-12-16 14:13:27.0,7数据库连接成功----------

----------2014-12-16 14:13:33.0,8数据库连接成功----------

----------2014-12-16 14:13:41.0,9数据库连接成功----------

---------2014-12-1614:13:47.0,10数据库连接成功----------

10个数据库连接都生效了,简直太神奇了,removeAbandoned确实回收了部分连接,所以10个数据库都能够连接,那么有了removeAbandoned 参数是不是就以后能解决连接池溢出的问题呢,答案是只能缓解连接池问题,不能彻底解决,而且要和removeAbandonedTimeout参数配套使用。

removeAbandonedTimeout 参数要和maxWait(业务逻辑)参数配套使用。

在上面的代码中,有一段代码为:Thread.sleep(6 * 1000);

如果把这段代码注释掉,马上就能看到6个数据库连接之后,异常马上就来了。

我们把这段的异常取下来:

异常太长了就不直接贴了。

我们在代码中加了p.setProperty("logAbandoned","true"); 如果把

/*                          p.setProperty("removeAbandoned","true");//移除不用的连接

p.setProperty("removeAbandonedTimeout","8");

p.setProperty("logAbandoned","true");*/

之后的异常也取下来,保持之后看差异在哪里。

人笨只好用力做,把两端异常拿下来仔细分析,有那么一点点差异。

Caused by: java.util.NoSuchElementException:Timeout waiting for idle object

atorg.apache.commons.pool.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:1174)

atorg.apache.commons.dbcp.AbandonedObjectPool.borrowObject(AbandonedObjectPool.java:79)

atorg.apache.commons.dbcp.PoolingDataSource.getConnection(PoolingDataSource.java:106)

... 4 more

org.apache.commons.dbcp.AbandonedObjectPool.borrowObject(AbandonedObjectPool.java:79)有一点差异。

但是根据网上搜索到的资料,“logAbandoned=true的话,将会在回收事件后,在log中打印出回收Connection的错误信息,包括在哪个地方用了Connection却忘记关闭了,在调试的时候很有用。”

尝试了一些方法和时间,没有找到这个要怎么测试,只能先放下,等以后遇到了这个问题再来记录。

经过一些测试后发现,这个日志不是一出现数据库连接池没有关闭就会被打印出来,需要一定的触发调整。在“Apache DBCP连接数据库异常重连”章节中的用例,出现了logAbandoned 打印出来的日志,养在深闺人未识啊,特摘录下来:这个日志,比较明确指出了那些地方数据库连接池没有关闭。

 

attest.ffm83.commons.dbcp.DbcpErrorConnection.main(DbcpErrorConnection.java:71)

org.apache.commons.dbcp.AbandonedTrace$AbandonedObjectException: DBCP object created 2014-12-16 15:41:53 by the following code was neverclosed:

atorg.apache.commons.dbcp.AbandonedTrace.init(AbandonedTrace.java:90)

atorg.apache.commons.dbcp.AbandonedTrace.<init>(AbandonedTrace.java:73)

atorg.apache.commons.dbcp.DelegatingStatement.<init>(DelegatingStatement.java:61)

atorg.apache.commons.dbcp.DelegatingPreparedStatement.<init>(DelegatingPreparedStatement.java:70)

atorg.apache.commons.dbcp.DelegatingConnection.prepareStatement(DelegatingConnection.java:281)

时间: 2024-11-02 21:28:35

Apache DBCP数据库连接池溢出调整的相关文章

DBCP数据库连接池-方式2手动创建

DBCPUtils.java package com.itheima.b_dbcp; import java.sql.Connection; import java.sql.SQLException; import org.apache.commons.dbcp.BasicDataSource; public class DBCPUtils { private static BasicDataSource dataSource ; static{ try { // 手动创建连接池 dataSou

DBCP数据库连接池——可适用DB2数据库

前提:     项目导入DB2的驱动jar包 驱动包 下载 >关于DBCP DBCP(DataBase connection pool),数据库连接池.是 apache 上的一个 java 连接池项目,也是 tomcat 使用的连接池组件.单独使用dbcp需要3个包:commons-dbcp.jar,commons-pool.jar,commons-collections.jar由于建立数据库连接是一个非常耗时耗资源的行为,所以通过连接池预先同数据库建立一些连接,放在内存中,应用程序需要建立数据

DBCP数据库连接池连接mysql数据库的时候 出现连接问题

在部署的项目的时候发现两个问题 ,第一个问题不是太容易发现 ,因为我部署的时候没问题 ,但是产品的同事在跑流程的时候总是出现一个connetException异常  自己看了半天没发现什么问题 去网上查了一下 说是msql的连接默认是八个小时 第二个问题就是 自己这边的数据库 隔一段时间不用的话 会自动断开  查了一下资料 是dbcp连接mysql时出现的这个问题  实际上两个问题算是一个问题吧 自己配置了一下 这几天没报这样的错误 !算是解决了吧!  <bean id="dataSour

解决dbcp数据库连接池错误

使用dbcp数据库连接池时报错 java.lang.NoClassDefFoundError: org/apache/commons/pool2/PooledObjectFactory原因:缺少commons-pool2-2.4.2.jarcommons-dbcp2-2.1.1.jar 原文地址:http://blog.51cto.com/59465168/2071979

【Java EE 学习第16天】【dbcp数据库连接池】【c3p0数据库连接池】

零.回顾之前使用的动态代理的方式实现的数据库连接池: 代码: 1 package day16.utils; 2 3 import java.io.IOException; 4 import java.lang.reflect.InvocationHandler; 5 import java.lang.reflect.Method; 6 import java.lang.reflect.Proxy; 7 import java.sql.Connection; 8 import java.sql.D

DBCP数据库连接池和 c3p0数据库连接池的使用

DBCP数据库连接池 http://m.blog.csdn.net/article/details?id=47033595 c3p0数据库连接池的使用 http://blog.csdn.net/wushangjimo/article/details/12654491

dbcp数据库连接池属性介绍

#最大连接数量:连接池在同一时间能够分配的最大活动连接的数量,,如果设置为非正数则表示不限制,默认值8 maxActive=15 #最小空闲连接:连接池中容许保持空闲状态的最小连接数量,低于这个数量将创建新的连接,如果设置为0则不创建,默认值0 minIdle=5 #最大空闲连接:连接池中容许保持空闲状态的最大连接数量,超过的空闲连接将被释放,如果设置为负数表示不限制,默认值8 maxIdle=10 #初始化连接数:连接池启动时创建的初始化连接数量,默认值0 initialSize=5 #连接被

DBCP数据库连接池的简单使用

0.DBCP简介      DBCP(DataBase connection pool)数据库连接池是 apache 上的一个Java连接池项目.DBCP通过连接池预先同数据库建立一些连接放在内存中(即连接池中),应用程序需要建立数据库连接时直接到从接池中申请一个连接使用,用完后由连接池回收该连接,从而达到连接复用,减少资源消耗的目的. 1.DBCP所依赖的jar包(以下例子基于如下jar包版本)    commons-dbcp2-2.1.1.jar       commons-logging-

使用Apache DBCP连接池重构DBUtility,让连接数据库更有效,更安全

直接使用JDBC访问数据库时,需要避免以下隐患: 1. 每一次数据操作请求都需要建立数据库连接.打开连接.存取数据和关闭连接等步骤.而建立和打开数据库连接是一件既耗资源又费时的过程,如果频繁发生这种数据库操作,势必会使系统性能下降. 2. 连接对象代表着数据库系统的连接进程,是有限的资源.如果系统的使用用户非常多,有可能超出数据库服务器的承受极限,造成系统的崩溃. 数据库连接池是解决上述问题最常用的方法.所谓连接池,即可以创建并持有数据库连接的组件.连接池可以预先创建并封装一些连接对象并将其缓存