Java主流常用的数据库连接池

主流的第三方数据库连接池

在实际应用中,通常不需要我们自己编写数据库连接池,目前市面上已经有很多组织提供了数据库连接池,常见的主要有下面几个:

  • C3p0
    开源的,成熟的,高并发第三方数据库连接池,作者是 Steve Waldman,相关的文档资料比较完善,大名鼎鼎的hibernate框架就使用了c3p0数据库连接池。
    项目地址:http://www.mchange.com/projects/c3p0/index.html
  • dbcp
    全称是DataBase Connection Pool,它是由Apache开发的一个数据库连接池,在tomcat7版本之前都是使用dbcp作为数据库连接池,不过dbcp性能不太好,apache又开发了tomcat jdbc pool来替代dbcp。
    项目地址:http://commons.apache.org/proper/commons-dbcp/
  • tomcat jdbc pool
    由于dbcp的性能不太好,apache又新开发了一款数据库连接池-tomcat jdbc pool,有的地方也称之为JDBC Connection Pool。
    项目地址:http://tomcat.apache.org/tomcat-9.0-doc/jdbc-pool.html
  • Druid
    作者是阿里巴巴的wenshao,号称是Java语言中最好的数据库连接池。Druid能够提供强大的监控和扩展功能。
    项目地址:https://github.com/alibaba/druid
  • BoneCP
    其官方说该数据库连接池性能非常棒,不过现在已经不更新了,转到了HiKariCP上。
    项目地址:http://www.jolbox.com/
  • HiKariCP
    Hikari是日语光的意思,作者可能想以此来表达HiKariCP速度之快。比之前的BoneCP性能更加强大,它官方展示了一些性能对比的数据,通过数据可以看出HiKariCP完虐c3p0,dbcp,tomcat jdbc pool等其他数据库连接池。并且它的库文件差不多就130kb,非常轻巧。
    项目地址:https://github.com/brettwooldridge/HikariCP
  • Proxool
    早期的一些项目中使用的多一些,现在该数据库连接池源码已经有一阵子不更新了。
    项目地址:http://proxool.sourceforge.net/

以上是目前市面上一些主流的数据库连接池基本是就是这些了,太多了,咱们就选两个简单介绍下, 通常在实际应用中会将数据库连接池和spring等常用框架配置在一起使用,因为框架还目前咱们还没有讲,所以先看下在不使用框架的前提下,该如何使用数据库连接池 。

c3p0

第一步:
下载相关jar包:
百度网盘:https://pan.baidu.com/s/1nwhU553
下载后将项目两个jar包拷贝到项目中

  • c3p0-0.9.5.2.jar
  • mchange-commons-java-0.2.11.jar

在稍微旧点的版本中只需要拷贝一个c3p0的jar就行,后来c3p0将里面的一些模块分离出来,就有了mchange-commons-java的jar了。
另外不要忘记拷贝数据库的驱动jar包。

第二步:
在项目的src目录下创建c3p0-config.xml文件,当然你也可以创建一个c3p0.properties文件,这两个都支持。在xml文件编写下面内容:

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
  <default-config>
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql://localhost:3306/test-pool</property>
    <property name="user">root</property>
    <property name="password">monkey1024</property>
    <!-- 初始化连接的数量 -->
    <property name="initialPoolSize">10</property>
    <!-- 最大空闲时间,单位是秒 -->
    <property name="maxIdleTime">30</property>
    <!-- 池中最大连接的数量 -->
    <property name="maxPoolSize">100</property>
    <!-- 池中最小连接的数量 -->
    <property name="minPoolSize">10</property>
  </default-config>
</c3p0-config>

第三步:
创建一个数据库test-pool,里面创建一个测试表t_user,建表语句如下:

CREATE TABLE `t_user` (
  `id` varchar(10) NOT NULL,
  `name` varchar(45) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

第四步:
创建一个C3P0Util的工具类,内容如下:

package com.monkey1024.jdbc.util;

import java.sql.Connection;
import java.sql.SQLException;

import com.mchange.v2.c3p0.ComboPooledDataSource;

public class C3P0Util {
    // 得到一个c3p0的数据源
    private static ComboPooledDataSource dataSource = new ComboPooledDataSource();

    // 从数据源中得到一个连接对象
    // 这个返回的connection实际上是c3p0经过装饰之后的connection
    public static Connection getConnection() {
        try {
            return dataSource.getConnection();
        } catch (SQLException e) {
            throw new RuntimeException("服务器错误");
        }
    }

    //查看连接池的状态
    public static void poolStatus() {
        try {
            System.out.println("清闲的:" + dataSource.getNumIdleConnections());
            System.out.println("忙碌的:" + dataSource.getNumBusyConnections());
            System.out.println("所有的:" + dataSource.getNumConnections());
        } catch (SQLException e) {
            e.printStackTrace();
        }

    }

}

创建一个测试类C3P0Test:

package com.monkey1024.jdbc.test;

import java.sql.Connection;
import java.sql.PreparedStatement;

import com.monkey1024.jdbc.util.C3P0Util;

public class C3P0Test {

    public static void main(String[] args) {
        insert();
        try {
            //睡眠一下方便查看状态
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        C3P0Util.poolStatus();
    }

    public static void insert() {

        String sql = "insert into t_user(id,name) values('1030','jack')";
        try (Connection conn = C3P0Util.getConnection(); 
                PreparedStatement ps = conn.prepareStatement(sql)) {
            //查看连接池的状态
            C3P0Util.poolStatus();
            ps.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}

druid

这里介绍一下咱们国人写的druid,在性能方面表现不错。
第一步:
下载相关jar包:druid-1.1.8.jar
百度网盘:https://pan.baidu.com/s/1pMGwxZX

第二步:
创建dbconfig.properties配置文件,在文件中编写下面内容,druid可以根据url自动识别driverclass,所以在配置文件中可以省略:

url=jdbc:mysql://localhost:3306/test-pool
username=root
password=monkey1024
#初始化的连接个数
initialSize=10
#最大连接个数
maxActive=20
#最小连接个数
minIdle=10

第三步:
创建数据库,内容同上面的c3p0的第三步一样

第四步:

编写DruidUtil工具类:

package com.monkey1024.jdbc.util;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;

public class DruidUtil {
    // 得到一个Druid的数据源
    private static DruidDataSource dataSource = null;

    static{
        Properties properties = new Properties();
        try {
            //加载配置文件
            //properties.load(new FileInputStream("build/classes/dbconfig.properties"));
            //下面这种写法会从classpath下来查找配置文件
            properties.load(DruidUtil.class.getClassLoader().getResourceAsStream("dbconfig.properties"));
            //得到一个数据源 
            dataSource = (DruidDataSource)DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    // 从数据源中得到一个连接对象
    // 这个返回的connection实际上是Druid经过装饰之后的connection
    public static Connection getConnection() {
        try {
            return dataSource.getConnection();
        } catch (SQLException e) {
            throw new RuntimeException("服务器错误");
        }
    }


}

编写测试类DruidTest:

package com.monkey1024.jdbc.test;

import java.sql.Connection;
import java.sql.PreparedStatement;

import com.monkey1024.jdbc.util.DruidUtil;

public class DruidTest {

    public static void main(String[] args) {
        insert();
        try {
            //睡眠一下方便查看状态
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void insert() {

        String sql = "insert into t_user(id,name) values('12012','jack')";
        try (Connection conn = DruidUtil.getConnection(); 
                PreparedStatement ps = conn.prepareStatement(sql)) {
            ps.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}