DBCP、c3p0、Druid三大连接池区别

 

DBCP、c3p0、Druid三大连接池区别

一、连接池优势

如果一个项目中如果需要多个连接,如果一直获取连接,断开连接,这样比较浪费资源;

如果创建一个池,用池来管理Connection,这样就可以重复使用Connection。

有了池我们就不用自己来创建Connection,而是通过池来获取Connection对象。当使用完Connection后,调用Connection的close()方法也不会真的关闭Connection,而是把Connection“归还”给池。

池就可以再利用这个Connection对象了。这里我们常用的连接池有三种,分别是:DBCP连接池、C3P0连接池和DRUID连接池;

二、DBCP连接池

DBCP是一个依赖Jakarta commons-pool对象池机制的数据库连接池.DBCP可以直接的在应用程序中使用,Tomcat的数据源使用的就是DBCP;

使用连接池的第一项工作就是导包,这里需要的两个jar包分别是:

在使用写连接池工具类的时候,可以通过配置文件来连接数据库,配置文件中记录了连接数据库的驱动、URL、用户名和密码等信息;但要注意这里的文件后缀为:“.properties”。

把通过配置文件连接数据库的部分写在静态代码块中,随着类的加载只加载一次。出了连接数据库,还要提供一个获得数据源的方法和一个获取连接的方法;

下边是把连接池写成一个工具类的代码,写成工具类和直接使用的代码几乎相同,就不在重复的写了。

配置文件的部分内容:

代码:(配置文件的命名为:dbcp.properties

public class DBCPUtils {
    //首先定义私有的datasource
    private static DataSource datasource;
    //把配置文件部分放在静态代码块中,调用时直接加载
    static{
        try {
            //加载文件
            InputStream is=DBCPUtils.class.getClassLoader().getResourceAsStream("dbcp.properties");
            //实例化properties集合
            Properties prop=new Properties();    
            prop.load(is);        
            //首先加载核心类     
            datasource=BasicDataSourceFactory.createDataSource(prop);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    //提供获得数据源  
    public static DataSource getDataSource(){
        return datasource;
    }
    //提供获得连接     
    public static Connection getConnection() throws SQLException{
        return datasource.getConnection();
    }
}

在写成工具类后都要对外提供一个数据源DateSource和一个连接Connection。作用是,如果我们在进行数据库操作的时候要是使用DBUtils类的时候,就要使用QueryRunner核心类,而这个类在进行与数据库连接的时候只要一句代码:QueryRunner qr=newQueryRunner(数据源);

通过连接池获得:DBCPUtils.getDataSource()获得。如果不使用DBUtils工具类,我们就可以直接通过DBCPUtils .getConnection()来直接获得连接。

三、C3P0连接池

c3p0是一个开放源代码的JDBC连接池,它在lib目录中与Hibernate一起发布,包括了实现jdbc3和jdbc2扩展规范说明的Connection 和Statement 池的DataSources 对象。

使用连接池的第一项工作就是导包,这里需要的两个jar包分别是:

这种连接池在进行数据库的连接的时候有两种连接方法:使用配置文件和不使用配置文件两种。

当然使用配置文件的时候代码要简介的多,配置文件中同样是记录了连接数据库的驱动、URL、用户名和密码等信息。

(1)不使用配置文件的代码:三个步骤:

<1>、导入核心类:ComboPooledDataSource 

<2>、基本的四项设置,也就是设置驱动,URL,用户名和密码等四项。

<3>、其他四项。代码如下:

public class c3p0_test01 {
    public static void main(String[] args) throws Exception {
        //导入一个核心类
        ComboPooledDataSource  dataSource = new ComboPooledDataSource();
        //基本四项设置
        dataSource.setDriverClass("com.mysql.jdbc.Driver");
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/eeday09");
        dataSource.setUser("root");
        dataSource.setPassword("123");
        //其他四项设置
        dataSource.setInitialPoolSize(10);  //初始化连接个数
        dataSource.setMaxPoolSize(40);   //最大链接数
        dataSource.setMinPoolSize(5);  //设置最小链接数
        dataSource.setAcquireIncrement(2);    //设置每次增加的连接数
        Connection conn=dataSource.getConnection();      //进行数据库连接
        System.out.println(conn);
    }
}

(2)如果使用配置文件连接数据库,其中配置文件中的内容为:

使用配置文件进行连接的写法如下:

import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.apache.commons.dbutils.QueryRunner;
import com.mchange.v2.c3p0.ComboPooledDataSource;
 
public class C3P0Utils {
    //1、提供私有化的数据源    使用默认设置
    private static ComboPooledDataSource datasource=new ComboPooledDataSource();
    //使用命名配置
    //private static ComboPooledDataSource datasource =new ComboPooledDataSource("itheima");
    //2.提供对外的数据源
     public static DataSource getDataSource(){
        return datasource;    
    }
    //3.提供对外的链接  
    public static Connection getConnection() throws SQLException{
        return datasource.getConnection();
    }
}

在写成工具类后都要对外提供一个数据源DateSource和一个连接Connection。作用是,如果我们在进行数据库操作的时候要是使用DBUtils类的时候,就要使用QueryRunner核心类,而这个类在进行与数据库连接的时候只要一句代码:QueryRunner qr=newQueryRunner(数据源);

我们可以通过连接池获得:C3P0Utils.getDataSource() 获得。如果不使用DBUtils工具类,我们就可以直接通过C3P0Utils.getConnection()来直接获得连接。

四、Druid连接池 

Druid首先是一个数据库连接池。Druid是目前最好的数据库连接池,在功能、性能、扩展性方面,都超过其他数据库连接池,包括DBCP、C3P0、BoneCP、Proxool、JBoss DataSource。Druid已经在阿里巴巴部署了超过600个应用,经过一年多生产环境大规模部署的严苛考验。

它不仅仅是一个数据库连接池,它还包含一个ProxyDriver,一系列内置的JDBC组件库,一个 SQL Parser。支持所有JDBC兼容的数据库,包括Oracle、MySql、Derby、Postgresql、SQL Server、H2等等。Druid针对Oracle和MySql做了特别优化,比如Oracle的PS Cache内存占用优化,MySql的ping检测优化。Druid提供了MySql、Oracle、Postgresql、SQL-92的SQL的完整支持,这是一个手写的高性能SQL Parser,支持Visitor模式,使得分析SQL的抽象语法树很方便。简单SQL语句用时10微秒以内,复杂SQL用时30微秒。通过Druid提供的SQL Parser可以在JDBC层拦截SQL做相应处理,比如说分库分表、审计等。Druid防御SQL注入攻击的WallFilter就是通过Druid的SQL Parser分析语义实现的。

使用步骤:

1,使用连接池的第一项工作就是导包,这里需要的jar包分别是:druid-1.1.4.jar   1.1.4

2,druid.properties 文件内容:

# 配置数据库的连接参数
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/test
username=root
password=root
​
# 配置连接池的参数
initialSize=5
maxActive=10
maxWait=3000
maxIdle=6
minIdle=3

3,连接池工具类:

/**
1)创建私有静态数据源成员变量DataSource ds
2)在静态代码块中创建连接池
a)创建属性对象
b)从类路径下加载属性文件,得到输入流对象
c)通过工厂类创建一个数据源
3)创建公有的得到数据源的方法getDataSource()
4)创建得到连接对象的方法 getConnection()
5)创建释放资源的方法 close()
*/

/**
 * 连接池的工具类
 */
public class DataSourceUtils {
    //创建一个成员变量
    private static DataSource ds;
    /**
     * 加载的代码写在静态代码块中
     */
    static {
        try {
            Properties info = new Properties();
            //加载类路径下,即src目录下的druid.properties这个文件
            info.load(DataSourceUtils.class.getResourceAsStream("/druid.properties"));
            
            //读取属性文件创建连接池
            ds = DruidDataSourceFactory.createDataSource(info);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 得到数据源
     */
    public static DataSource getDataSource() {
        return ds;
    }
    /**
     * 得到连接对象
     */
    public static Connection getConnection() {
        try {
            return ds.getConnection();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
    /**
     * 释放资源
     */
    public static void close(Connection conn, Statement stmt, ResultSet rs) {
        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();
            }
        }
    }
    public static void close(Connection conn, Statement stmt) {
        close(conn, stmt, null);
    }
}

4,数据源工具类的使用:

public class DemoAdd {
    public static void main(String[] args) {
        //1. 创建连接对象,通过连接池工具类
        Connection conn = null;
        PreparedStatement ps = null;
        int row = 0;
        try {
            conn = DataSourceUtils.getConnection();
            //2. 创建语句对象
           ps = conn.prepareStatement("INSERT INTO student values(null,?,?,?)");
           ps.setString(1,"张辽");
           ps.setInt(2,1);
           ps.setString(3,"194-06-16");
           //3. 使用executeUpdate()写入到数据库
            row = ps.executeUpdate();
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            //4. 释放资源
            DataSourceUtils.close(conn, ps);
        }
        System.out.println("添加了" + row);
    }
}

五、三者区别

我们从连接池配置的基本配置、关键配置、性能配置等主要配置来分析:

1,基本配置

基本配置是指连接池进行数据库连接的四个基本必需配置:
传递给JDBC驱动的用于连接数据库的用户名、密码、URL以及驱动类名。

 注:在Druid连接池的配置中,driverClassName可配可不配,如果不配置会根据url自动识别dbType(数据库类型),然后选择相应的driverClassName。

2,关键配置

为了发挥数据库连接池的作用,在初始化时将创建一定数量的数据库连接放到连接池中,这些数据库连接的数量是由最小数据库连接数来设定的。无论这些数 据库连接是否被使用,连接池都将一直保证至少拥有这么多的连接数量。连接池的最大数据库连接数量限定了这个连接池能占有的最大连接数,当应用程序向连接池 请求的连接数超过最大连接数量时,这些请求将被加入到等待队列中。
最小连接数:是数据库一直保持的数据库连接数,所以如果应用程序对数据库连接的使用量不大,将有大量的数据库资源被浪费。
初始化连接数:连接池启动时创建的初始化数据库连接数量。
最大连接数:是连接池能申请的最大连接数,如果数据库连接请求超过此数,后面的数据库连接请求被加入到等待队列中。
最大等待时间:当没有可用连接时,连接池等待连接被归还的最大时间,超过时间则抛出异常,可设置参数为0或者负数使得无限等待(根据不同连接池配置)。

 

注1:在DBCP连接池的配置中,还有一个maxIdle的属性,表示最大空闲连接数,超过的空闲连接将被释放,默认值为8。对应的该属性在Druid连接池已不再使用,配置了也没有效果,c3p0连接池则没有对应的属性。

注2:数据库连接池在初始化的时候会创建initialSize个连接,当有数据库操作时,会从池中取出一个连接。如果当前池中正在使用的连接数等 于maxActive,则会等待一段时间,等待其他操作释放掉某一个连接,如果这个等待时间超过了maxWait,则会报错;如果当前正在使用的连接数没 有达到maxActive,则判断当前是否空闲连接,如果有则直接使用空闲连接,如果没有则新建立一个连接。在连接使用完毕后,不是将其物理连接关闭,而 是将其放入池中等待其他操作复用。

 3,性能配置

 (1)预缓存设置:

  即是PSCache,PSCache对支持游标的数据库性能提升巨大,比如说oracle。JDBC的标准参数,用以控制数据源内加载的 PreparedStatements数量。但由于预缓存的statements属于单个connection而不是整个连接池,所以设置这个参数需要考 虑到多方面的因素。
  单个连接拥有的最大缓存数:要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100

(2)连接有效性检测设置:

  连接池内部有机制判断,如果当前的总的连接数少于miniIdle,则会建立新的空闲连接,以保证连接数得到miniIdle。如果当前连接池中某 个连接在空闲了timeBetweenEvictionRunsMillis时间后任然没有使用,则被物理性的关闭掉。有些数据库连接的时候有超时限制 (mysql连接在8小时后断开),或者由于网络中断等原因,连接池的连接会出现失效的情况,这时候设置一个testWhileIdle参数为true, 可以保证连接池内部定时检测连接的可用性,不可用的连接会被抛弃或者重建,最大情况的保证从连接池中得到的Connection对象是可用的。当然,为了 保证绝对的可用性,你也可以使用testOnBorrow为true(即在获取Connection对象时检测其可用性),不过这样会影响性能。

(3)超时连接关闭设置:

  removeAbandoned参数,用来检测到当前使用的连接是否发生了连接泄露,所以在代码内部就假定如果一个连接建立连接的时间很长,则将其认定为泄露,继而强制将其关闭掉。

(4)c3p0重连设置:

  设置获取连接失败后,是否重新连接以及间隔时间。

六、DBCP、C3P0、DRUID三大连接池属性说明表

1,DBCP 属性说明表

2,C3P0  属性说明表

(3)DRUID 属性说明表

 

 

 

posted @ 2018-10-17 15:49  整合侠  阅读(3582)  评论(1编辑  收藏  举报