DBCP数据库连接池的简单使⽤
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配置⽂件>>
#驱动名
sql.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 
1package dbcp;
2
3import java.io.FileInputStream;
4import java.io.IOException;
5import java.sql.Connection;
6import java.sql.SQLException;
7import java.util.Properties;
8
9import javax.sql.DataSource;
10
11import org.apachemons.dbcp2.BasicDataSourceFactory;
12
13/**
14 * DBCP配置类
15 * @author SUN
16*/
17public class KCYDBCPUtil {
18
19private static Properties properties = new Properties();
20private static DataSource dataSource;
21//加载DBCP配置⽂件
22static{
23try{
24            FileInputStream is = new FileInputStream("config/dbcp.properties");
25            properties.load(is);
26        }catch(IOException e){
27            e.printStackTrace();
28        }
29
30try{
31            dataSource = ateDataSource(properties);
32        }catch(Exception e){
33            e.printStackTrace();
34        }
35    }
36
37//从连接池中获取⼀个连接
38public static Connection getConnection(){
39        Connection connection = null;
40try{
41            connection = Connection();
42        }catch(SQLException e){
43            e.printStackTrace();
44        }
45try {
46            connection.setAutoCommit(false);
47        } catch (SQLException e) {
48            e.printStackTrace();
49        }
50return connection;
51    }
52
53public static void main(String[] args) {
54        getConnection();
55    }
56 }
  3) 创建使⽤JDBC获取数据库连接的类DBConn.java(⽤于和DBCP连接池对⽐) 1package dbcp;
2
3import java.sql.Connection;
4import java.sql.DriverManager;
5
6public class DBConn {
7private static Connection conn = null;
8
9//获取⼀个数据库连接
10public static Connection getConnection() {
11try {
12            Class.forName("sql.jdbc.Driver");
13            isterDriver(sql.jdbc.Driver());
14            String dbUrl = "jdbc:mysql://127.0.0.1:3306/mydb";
15            conn = Connection(dbUrl, "sa", "123456");
16//            System.out.println("========数据库连接成功========");
17        } catch (Exception e) {
18            e.printStackTrace();
19//            System.out.println("========数据库连接失败========");
20return null;
21        }
22return conn;
23    }
24 }
  4) 创建测试类DBCPTest.java
    测试类中采⽤3中⽅法将2000个数据插⼊数据库同⼀张表中,每次插⼊数据之前,先清空表,并对结果进⾏了对⽐。
    3中插⼊数据⽅法如下:
    (1) 每次插⼊⼀条数据前,就创建⼀个连接,该条数据插⼊完成后,关闭该连接;
   (2) 使⽤DBCP连接池,每次插⼊⼀条数据前,从DBCP连接池中获取⼀条连接,该条数据插⼊完成后,该连接交由DBCP连接池管理;
    (3) 在插⼊数据之前创建⼀条连接,2000个数据全部使⽤该连接,2000个数据插⼊完毕后,关闭该连
接。
1package dbcp;
2
3import java.sql.Connection;
4import java.sql.SQLException;
5import java.sql.Statement;
6
7import org.junit.Test;
8
9public class DBCPTest {
10
11//测试,每写⼀条数据前,就新建⼀个连接
12    @Test
13public void testWriteDBByEveryConn() throws Exception{
14for(int i = 0; i < 2000; i++){
15            writeDBByEveryConn(i);
16        }
17        System.out.println("DONE");
18
19    }
20
21//测试,使⽤连接池,每写⼀条数据前,从连接池中获取⼀个连接
22    @Test
23public void testWriteDBByDBCP() throws Exception{
24for(int i = 0; i < 2000; i++){
25            writeDBByDBCP(i);
26        }
27        System.out.println("DONE");
28    }
29
30//测试,只建⼀条连接,写⼊所有数据
31    @Test
32public void testWriteDBByOneConn() throws Exception{
33        Connection conn = Connection();
34        Statement stat = ateStatement();
35for(int i = 0; i < 2000; i++){
36            writeDBByOneConn(i, stat);
37        }
38        conn.close();
39        System.out.println("DONE");
40    }
41
42//不使⽤连接池写数据库,每写⼀条数据创建⼀个连接
43public void writeDBByEveryConn(int data){
44        String sql = "insert into dbcp values (" + data + ")";
45        Connection conn = Connection();
46try{
47            Statement stat = ateStatement();
48            uteUpdate(sql);
49        }catch(Exception e){
50            e.printStackTrace() ;
51        }finally{
52try {
53                conn.close();
54            } catch (SQLException e) {
数据库简单吗55                e.printStackTrace();
56            }
57
58        }
59    }
60
61//不使⽤连接池写数据库,只⽤⼀个连接,写所有数据
62public void writeDBByOneConn(int data, Statement stat){
63        String sql = "insert into dbcp values (" + data + ")";
64try{
65            uteUpdate(sql);
66        }catch(Exception e){
67            e.printStackTrace() ;
68        }
69    }
70
71//通过DBCP连接池写数据库
72public void writeDBByDBCP(int data){
73        String sql = "insert into dbcp values (" + data + ")";
74try {
75            Connection conn = Connection();
76            Statement stat = ateStatement();
77            uteUpdate(sql);
78            connmit();
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=true和removeAbandonedTimeout=1配置项的作⽤
    将测试类DBCPTest.java的writeDBByDBCP(int data)⽅法修改为如下:
1//通过DBCP连接池写数据库
2public void writeDBByDBCP(int data){
3        String sql = "insert into dbcp values (" + data + ")";
4try {
5            Connection conn = Connection();
6            Statement stat = ateStatement();
7            uteUpdate(sql);
8            connmit();
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条数据时报错。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。

发表评论