0、DBCP简介

     DBCP(DataBase connection pool)数据库连接池是 apache 上的一个Java连接池项目。DBCP通过连接池预先同数据库建立一些连接放在内存中(即连接池中),应用程序需要建立数据库连接时直接到从接池中申请一个连接使用,用完后由连接池回收该连接,从而达到连接复用,减少资源消耗的目的。

1、DBCP所依赖的jar包(以下例子基于如下jar包版本)

   commons-dbcp2-2.1.1.jar       commons-logging-1.2.jar       commons-pool2-2.4.2.jar

2、DBCP使用示例

  下图是在Eclipse中创建的Java工程,使用了DBCP相关的jar包,mysql的jdbc驱动jar包,junit4 。

   并在src同级目录下创建了config目录,用于存放DBCP的配置文件。

【注】类DBCPUtil.java在下面的例子中未用到。

  

  1) DBCP配置文件dbcp.properties

########DBCP配置文件##########
#驱动名driverClassName=com.mysql.jdbc.Driver#urlurl=jdbc:mysql://127.0.0.1:3306/mydb#用户名username=sa#密码password=123456#初试连接数initialSize=30#最大活跃数maxTotal=30#最大idle数maxIdle=10#最小idle数minIdle=5#最长等待时间(毫秒)maxWaitMillis=1000#程序中的连接不使用后是否被连接池回收(该版本要使用removeAbandonedOnMaintenance和removeAbandonedOnBorrow)#removeAbandoned=trueremoveAbandonedOnMaintenance=trueremoveAbandonedOnBorrow=true#连接在所指定的秒数内未使用才会被删除(秒)(为配合测试程序才配置为1秒)removeAbandonedTimeout=1

  

  2) 创建初始化DBCP的类KCYDBCPUtil.java  

  package dbcp;

  import java.io.FileInputStream;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties; import javax.sql.DataSource; import org.apache.commons.dbcp2.BasicDataSourceFactory; /**
* DBCP配置类
* @author SUN
*/
public class KCYDBCPUtil { private static Properties properties = new Properties();
private static DataSource dataSource;
//加载DBCP配置文件
static{
try{
FileInputStream is = new FileInputStream("config/dbcp.properties");
properties.load(is);
}catch(IOException e){
e.printStackTrace();
} try{
dataSource = BasicDataSourceFactory.createDataSource(properties);
}catch(Exception e){
e.printStackTrace();
}
} //从连接池中获取一个连接
public static Connection getConnection(){
Connection connection = null;
try{
connection = dataSource.getConnection();
}catch(SQLException e){
e.printStackTrace();
}
try {
connection.setAutoCommit(false);
} catch (SQLException e) {
e.printStackTrace();
}
return connection;
} public static void main(String[] args) {
getConnection();
}
}

  3) 创建使用JDBC获取数据库连接的类DBConn.java(用于和DBCP连接池对比)

  import java.sql.Connection;
import java.sql.DriverManager; public class DBConn {
private static Connection conn = null; //获取一个数据库连接
public static Connection getConnection() {
try {
Class.forName("com.mysql.jdbc.Driver");
DriverManager.registerDriver(new com.mysql.jdbc.Driver());
String dbUrl = "jdbc:mysql://127.0.0.1:3306/mydb";
conn = DriverManager.getConnection(dbUrl, "sa", "123456");
// System.out.println("========数据库连接成功========");
} catch (Exception e) {
e.printStackTrace();
// System.out.println("========数据库连接失败========");
return null;
}
return conn;
}
}

  4) 创建测试类DBCPTest.java

    测试类中采用3中方法将2000个数据插入数据库同一张表中,每次插入数据之前,先清空表,并对结果进行了对比。

    3中插入数据方法如下:

    (1) 每次插入一条数据前,就创建一个连接,该条数据插入完成后,关闭该连接;

   (2) 使用DBCP连接池,每次插入一条数据前,从DBCP连接池中获取一条连接,该条数据插入完成后,该连接交由DBCP连接池管理;

    (3) 在插入数据之前创建一条连接,2000个数据全部使用该连接,2000个数据插入完毕后,关闭该连接。

  package dbcp;

  import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement; import org.junit.Test; public class DBCPTest { //测试,每写一条数据前,就新建一个连接
@Test
public void testWriteDBByEveryConn() throws Exception{
for(int i = 0; i < 2000; i++){
writeDBByEveryConn(i);
}
System.out.println("DONE"); } //测试,使用连接池,每写一条数据前,从连接池中获取一个连接
@Test
public void testWriteDBByDBCP() throws Exception{
for(int i = 0; i < 2000; i++){
writeDBByDBCP(i);
}
System.out.println("DONE");
} //测试,只建一条连接,写入所有数据
@Test
public void testWriteDBByOneConn() throws Exception{
Connection conn = DBConn.getConnection();
Statement stat = conn.createStatement();
for(int i = 0; i < 2000; i++){
writeDBByOneConn(i, stat);
}
conn.close();
System.out.println("DONE");
} //不使用连接池写数据库,每写一条数据创建一个连接
public void writeDBByEveryConn(int data){
String sql = "insert into dbcp values (" + data + ")";
Connection conn = DBConn.getConnection();
try{
Statement stat = conn.createStatement();
stat.executeUpdate(sql);
}catch(Exception e){
e.printStackTrace() ;
}finally{
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
} }
} //不使用连接池写数据库,只用一个连接,写所有数据
public void writeDBByOneConn(int data, Statement stat){
String sql = "insert into dbcp values (" + data + ")";
try{
stat.executeUpdate(sql);
}catch(Exception e){
e.printStackTrace() ;
}
} //通过DBCP连接池写数据库
public void writeDBByDBCP(int data){
String sql = "insert into dbcp values (" + data + ")";
try {
Connection conn = KCYDBCPUtil.getConnection();
Statement stat = conn.createStatement();
stat.executeUpdate(sql);
conn.commit();
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
} } 

  测试结果如下:

  (1) 每次插入一条数据前,就创建一个连接,该条数据插入完成后,关闭该连接。耗时158.318秒

   

  (2) 使用DBCP连接池,每次插入一条数据前,从DBCP连接池中获取一条连接,该条数据插入完成后,该连接交由DBCP连接池管理。耗时122.404秒

   

  (3) 在插入数据之前创建一条连接,2000个数据全部使用该连接,2000个数据插入完毕后,关闭该连接。耗时117.87秒

   

  通过对比结果看出,向同一个表中插入2000条数据,每插入一条数据前创建一个新连接,会非常耗时,而使用DBCP连接池和使用同一个连接操作,耗时比较接近。

3、相关问题

  1) 应用程序中,使用完一个数据库连接后,DBCP连接池如何管理该连接。

   分两种情况:

    (1) 应用程序中主动关闭该连接,即DBCPTest.java中第79行  conn.close();

     这种情况并不是手动将该连接关闭,而是将该连接交回给DBCP连接池,由连接池管理该连接。即用完连接后显示的将数据库连接提交至DBCP连接池。

    (2) 应用程序中不关闭该连接,即将DBCPTest.java中第79行  conn.close()注释掉

     这种情况DBCP配置文件dbcp.properties中的配置项(注意jar包版本,低版本中使用removeAbandoned=true配置项) 

     removeAbandonedOnMaintenance=true
        removeAbandonedOnBorrow=true

      removeAbandonedTimeout=1

      会起作用,removeAbandonedOnMaintenance=true和removeAbandonedOnBorrow=true表示DBCP连接池自动管理应程序中使用完毕的连接,removeAbandonedTimeout=1表示一个连接在程序中使用完毕后,若在1秒之内没有再次使用,则DBCP连接池回收该连接(通常removeAbandonedTimeout不会配置1,此处为了测试使用)。

    (3) 验证removeAbandonedOnMaintenance=true、removeAbandonedOnBorrow=true和removeAbandonedTimeout=1配置项的作用

       将测试类DBCPTest.java的writeDBByDBCP(int data)方法修改为如下:

      //通过DBCP连接池写数据库
public void writeDBByDBCP(int data){
String sql = "insert into dbcp values (" + data + ")";
try {
Connection conn = KCYDBCPUtil.getConnection();
Statement stat = conn.createStatement();
stat.executeUpdate(sql);
conn.commit();
// conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}

    重新执行testWriteDBByDBCP()方法,结果如下:

    

    可见writeDBByDBCP(int data)方法修改后和修改前作用相同,说明连接使用完后,由DBCP连接池管理。

    而如果将修改配置项removeAbandonedTimeout=180,即一个连接用完后会等待180秒,超过180秒后才由DBCP连接池回收,重新执行testWriteDBByDBCP()方法,执行一段时间后报错(Cannot get a connection, pool error Timeout waiting for idle object),如下:

    

    此时,查询数据表,发现正好插入了30条数据,如下:

    

    这说明在插入第31条数据的时候报错,错误原因是连接池中没有可用的连接了。这是因为DBCP连接池初始化连接数为30,removeAbandonedTimeout设为180秒,所以30个连接用完后,程序运行还未 到180秒,程序中用完的连接都还没有被DBCP连接池回收,所以DBCP连接池中没有可用的连接了,才会在插入第31条数据时报错。

DBCP数据库连接池的简单使用的更多相关文章

  1. 【Java EE 学习 16 上】【dbcp数据库连接池】【c3p0数据库连接池】

    一.回顾之前使用的动态代理的方式实现的数据库连接池: 代码: package day16.utils; import java.io.IOException; import java.lang.ref ...

  2. java数据库连接池技术简单使用

    JDBCDemo.java: package com.itheima.jdbc; import java.sql.Connection; import java.sql.PreparedStateme ...

  3. 一次项目实践中DBCP数据库连接池性能优化

    关于数据库连接池DBCP的关注源于刚刚结束的一轮测试,测试内容是衡量某Webserver服务创建用户接口的性能.这是一款典型的tomcat应用,使用的测试工具是Grinder.DBCP作为tomcat ...

  4. DBCP数据库连接池的使用

    DBCP的简单介绍: DBCP(DataBase Connection Pool)数据库连接池,是java数据库连接池的一种,由apache开发通过数据库连接池可以让程序自动管理数据库连接的释放和断开 ...

  5. DBCP数据库连接池

    在用JDBC连接数据库的时候,需要创建对数据库的连接,这样才能执行后续的操作.然而,这样做有两个问题: 数据库允许的连接个数有限 创建连接的过程需要消耗内存和时间 所以,JDBC引入了连接池的概念.也 ...

  6. java基础之JDBC六:DBCP 数据库连接池简介

    我们之前写的代码中的数据库连接每次都是自己创建,用完以后自己close()销毁的,这样是很耗费资源的,所以我们引入DBCP DBCP简介 概述: Data Base Connection Pool, ...

  7. DBCP数据库连接池原理分析

    在比较大的项目中,需要不断的从数据库中获取数据,Java中则使用JDBC连接数据库,但是获取数据库的连接可是相当耗时的操作,每次连接数据库都获得 .销毁数据库连接,将是很大的一个开销.为了解决这种开销 ...

  8. DBCP数据库连接池初探

    1. 概述 数据库连接是很“宝贵的”,如果每次获取Connection都去创建数据库连接,使用之后就断开,再次使用又重新创建,程序效率是很低的.因为Socket连接的建立很消耗资源. 所以需要数据库连 ...

  9. 03_dbcp数据源依赖jar包,DBCP中API介绍,不同过dbcp方式使用dbcp数据库连接池,通过配置文件使用dbcp数据库连接池

     DBCP数据源 使用DBCP数据源,需要导入两个jar包 Commons-dbcp.jar:连接池的实现 Common-pool.jar:连接池实现的依赖库. 导入mysql的jar包. DBC ...

随机推荐

  1. 解决nexus3报Cannot open local storage 'component' with mode=rw的异常问题

    起因:正常使用的公司Maven.Docker私有仓库,突然镜像不能推送,返回getsockopt: connection refused,用docker客户端登录也是返回同样的错误,查看nexus3日 ...

  2. Android架构设计之插件化、组件化

    如今移动app市场已经是百花齐放,其中有不乏有很多大型公司.巨型公司都是通过app创业发展起来的:app类型更加丰富,有电子商务.有视频.有社交.有工具等等,基本上涵盖了各行各业每个角落,为了更加具有 ...

  3. BaseActivity合集

    1.出自“高仿京东商城”: package com.itau.jingdong.ui.base; import com.itau.jingdong.AppManager; import com.ita ...

  4. 线性表接口的实现_Java

    线性表是其组成元素间具有线性关系的一种线性结构,对线性表的基本操作主要有插入.删除.查找.替换等,这些操作可以在线性表的任何位置进行.线性表可以采用顺序存储结构和链式存储结构表示. 本接口的类属于da ...

  5. 三层构架 和 MVC 是什么?

    作者:肖继潮链接:https://www.zhihu.com/question/24291079/answer/27339010著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 企 ...

  6. Software Testing Techniques Homework 1

    I have met some errors in recent years, one of them which impress me most. It happend when I try to ...

  7. Python 装饰器的总结

    先来了解几个定义: 1,函数 在python中,函数通过def关键字.函数名和可选的参数列表定义.通过return关键字返回值.我们举例来说明如何定义和调用一个简单的函数: #coding:UTF8 ...

  8. 微信开发平台中有个接口是上传多媒体文件,我用的是java 开发的,我怎么样才能在后台实现呢?

    /**      * 文件上传到微信服务器      * @param fileType 文件类型      * @param filePath 文件路径      * @return JSONObj ...

  9. C++通过Callback向C#传递数据

    现在比较流行C#与C++融合:C#做GUI,开发效率高,C++做运算,运行效率高,二者兼得. 但是C++与C#必然存在数据交互,C#与C++dll的数据交互从来都是一个让人头疼的问题. 从调用方式看也 ...

  10. 关于Oracle伪列rownum

    rownum列跟rowid列不一样,虽然同为表的伪列.但是rowid列是列的一个固定属性,而rownum列是结果集的一个排序.所以像如下查询是不会返回结果的:select rowid,rownum,e ...