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

来源:互联网 发布:matlab去雾算法 编辑:程序博客网 时间:2024/04/28 11:54

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
#url
url=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=true
removeAbandonedOnMaintenance=true
removeAbandonedOnBorrow=true
#连接在所指定的秒数内未使用才会被删除(秒)(为配合测试程序才配置为1秒)
removeAbandonedTimeout=1

复制代码

   

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

复制代码
 1 package dbcp; 2  3 import java.io.FileInputStream; 4 import java.io.IOException; 5 import java.sql.Connection; 6 import java.sql.SQLException; 7 import java.util.Properties; 8  9 import javax.sql.DataSource;10 11 import org.apache.commons.dbcp2.BasicDataSourceFactory;12 13 /**14  * DBCP配置类15  * @author SUN16  */17 public class KCYDBCPUtil {18     19     private static Properties properties = new Properties();20     private static DataSource dataSource;21     //加载DBCP配置文件22     static{23         try{24             FileInputStream is = new FileInputStream("config/dbcp.properties");  25             properties.load(is);26         }catch(IOException e){27             e.printStackTrace();28         }29         30         try{31             dataSource = BasicDataSourceFactory.createDataSource(properties);32         }catch(Exception e){33             e.printStackTrace();34         }35     }36     37     //从连接池中获取一个连接38     public static Connection getConnection(){39         Connection connection = null;40         try{41             connection = dataSource.getConnection();42         }catch(SQLException e){43             e.printStackTrace();44         }45         try {46             connection.setAutoCommit(false);47         } catch (SQLException e) {48             e.printStackTrace();49         }50         return connection;51     }52     53     public static void main(String[] args) {54         getConnection();55     }56 }
复制代码

 

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

复制代码
 1 package dbcp; 2  3 import java.sql.Connection; 4 import java.sql.DriverManager; 5  6 public class DBConn { 7     private static Connection conn = null; 8      9     //获取一个数据库连接10     public static Connection getConnection() {11         try {12             Class.forName("com.mysql.jdbc.Driver");13             DriverManager.registerDriver(new com.mysql.jdbc.Driver());14             String dbUrl = "jdbc:mysql://127.0.0.1:3306/mydb";15             conn = DriverManager.getConnection(dbUrl, "sa", "123456");16 //            System.out.println("========数据库连接成功========");17         } catch (Exception e) {18             e.printStackTrace();19 //            System.out.println("========数据库连接失败========");20             return null;21         }22         return conn;23     }24 }
复制代码

 

   4) 创建测试类DBCPTest.java

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

    3中插入数据方法如下:

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

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

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

复制代码
 1 package dbcp; 2  3 import java.sql.Connection; 4 import java.sql.SQLException; 5 import java.sql.Statement; 6  7 import org.junit.Test; 8  9 public class DBCPTest {10     11     //测试,每写一条数据前,就新建一个连接12     @Test13     public void testWriteDBByEveryConn() throws Exception{14         for(int i = 0; i < 2000; i++){15             writeDBByEveryConn(i);16         }17         System.out.println("DONE");18         19     }20     21     //测试,使用连接池,每写一条数据前,从连接池中获取一个连接22     @Test23     public void testWriteDBByDBCP() throws Exception{24         for(int i = 0; i < 2000; i++){25             writeDBByDBCP(i);26         }27         System.out.println("DONE");28     }29     30     //测试,只建一条连接,写入所有数据31     @Test32     public void testWriteDBByOneConn() throws Exception{33         Connection conn = DBConn.getConnection();34         Statement stat = conn.createStatement();35         for(int i = 0; i < 2000; i++){36             writeDBByOneConn(i, stat);37         }38         conn.close();39         System.out.println("DONE");40     }41     42     //不使用连接池写数据库,每写一条数据创建一个连接43     public void writeDBByEveryConn(int data){44         String sql = "insert into dbcp values (" + data + ")"; 45         Connection conn = DBConn.getConnection();46         try{    47             Statement stat = conn.createStatement();48             stat.executeUpdate(sql);            49         }catch(Exception e){50             e.printStackTrace() ;51         }finally{52             try {    53                 conn.close();    54             } catch (SQLException e) {55                 e.printStackTrace();56             }57             58         }59     }60     61     //不使用连接池写数据库,只用一个连接,写所有数据62     public void writeDBByOneConn(int data, Statement stat){63         String sql = "insert into dbcp values (" + data + ")"; 64         try{    65             stat.executeUpdate(sql);            66         }catch(Exception e){67             e.printStackTrace() ;68         }69     }70     71     //通过DBCP连接池写数据库72     public void writeDBByDBCP(int data){ 73         String sql = "insert into dbcp values (" + data + ")"; 74         try {75             Connection conn = KCYDBCPUtil.getConnection();  76             Statement stat = conn.createStatement();77             stat.executeUpdate(sql);78             conn.commit();79             conn.close();80         } catch (SQLException e) {   81             e.printStackTrace();  82         }83     }84 85 } 
复制代码

  测试结果如下:

  (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=trueremoveAbandonedTimeout=1配置项的作用

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

复制代码
 1     //通过DBCP连接池写数据库 2     public void writeDBByDBCP(int data){  3         String sql = "insert into dbcp values (" + data + ")";  4         try { 5             Connection conn = KCYDBCPUtil.getConnection();   6             Statement stat = conn.createStatement(); 7             stat.executeUpdate(sql); 8             conn.commit(); 9 //            conn.close();10         } catch (SQLException e) {   11             e.printStackTrace();  12         }13     }
复制代码

 

    重新执行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条数据时报错。

转自:https://www.cnblogs.com/sunseine/p/5947448.html

阅读全文
'); })();
0 0
原创粉丝点击
热门IT博客
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 四二拍打拍子手势图解 三拍子指挥图示 三拍子的儿歌 羽毛球拍子什么牌子好 水谷隼朝刘国梁扔拍子 丰顺路宝拍车网 宝拍相机 拍宝 正常骨科拍一张片子多少钱 张拍芝图片 张拍芝个人资料 拍一张艺术照多少钱 婚纱照拍几张 拍一张婚纱照多少钱 拍张婚纱照多少钱 拍一张婚纱照要多少钱 单行线逆行需要拍几张 拍手歌 拍手歌大全 拍手称快 拍手歌谣 幸福拍手歌 拍手歌课文 拍手歌教案 动物拍手歌 拍手歌反思 拍手 拍手联盟 拍手顺口溜 拍手歌词 卫生拍手歌 鬼拍手 拍手点头 拍手英语 拍手歌歌词 自编拍手歌 拍手儿歌 拍手图片 编拍手歌 拍手舞 拍手的好处