一、什么是数据库连接池?

官方:数据库连接池(Connection pooling)是程序启动时建立足够的数据库连接,并将这些连接组成一个连接池,由程序动态地对池中的连接进行申请,使用,释放。
个人理解:创建数据库连接是一个很耗时的操作,也容易对数据库造成安全隐患。所以,在程序初始化的时候,集中创建多个数据库连接,并把他们集中管理,供程序使用,可以保证较快的数据库读写速度,还更加安全可靠。

二、数据库连接池的运行机制

(1) 程序初始化时创建连接池
(2) 使用时向连接池申请可用连接
(3) 使用完毕,将连接返还给连接池
(4) 程序退出时,断开所有连接,并释放资源

三、数据库连接池的使用

作为开源的数据库连接池,C3P0是一个优秀的连接池,性能也十分可靠。

德鲁伊连接池mergesql_数据库


Druid 连接池简介

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

同时Druid不仅仅是一个数据库连接池,它包括四个部分:

Druid是一个JDBC组件,它包括三个部分:
基于Filter-Chain模式的插件体系。
DruidDataSource 高效可管理的数据库连接池。
SQLParser

Druid的功能

1、替换DBCP和C3P0。Druid提供了一个高效、功能强大、可扩展性好的数据库连接池。
2、可以监控数据库访问性能,Druid内置提供了一个功能强大的StatFilter插件,能够详细统计SQL的执行性能,这对于线上分析数据库访问性能有帮助。
3、数据库密码加密。直接把数据库密码写在配置文件中,这是不好的行为,容易导致安全问题。DruidDruiver和DruidDataSource都支持PasswordCallback。
4、SQL执行日志,Druid提供了不同的LogFilter,能够支持Common-Logging、Log4j和JdkLog,你可以按需要选择相应的LogFilter,监控你应用的数据库访问情况。
5、扩展JDBC,如果你要对JDBC层有编程的需求,可以通过Druid提供的Filter机制,很方便编写JDBC层的扩展插件。

使用原因

原先项目使用的是C3P0连接池,在项目发布使用一段时间后发现c3p0 连接池访问数据库的时候创建连接会在oralce的lisenter.log 日志文件记录。

经过一段时间观察发现oralce每6秒会在lisenter.log日志记录一次,我们设置的最小连接是20,所以oracle每次会在日志记录20条。随着时间越长日志文件越来越大,当日志文件达到4个G的时候会导致oracle死掉。 经过不断调整参数配置还是无法得到解决方案,最后选择使用阿里Druid连接池试试,Druid默认最小连接2个,配置好后发布观察日志发现只在创建的时候在日志里面记录了2条记录。没有像C3P0那样每6秒记录一次导致日志文件越来越大。

lisenter.log 日志截图

德鲁伊连接池mergesql_数据库_02

Druid使用

1. Druid.jar包

druid-1.1.22.jar 1.1.4

首先到http://sourceforge.net/projects/c3p0/下载相应的jar包,总共三个,如下图所示。

德鲁伊连接池mergesql_mysql_03


其次将jar包导入到工程当中,然后就可以使用c3p0和Druid了。

c3p0和Druid连接池示例代码如下(代码就不分文件了最基础的连接就不放代码了,直接第二种连接池技术放一起,不需要另一种连接池就直接注释掉就好):
JDBCUtils.java文件

package testConnection;

import com.alibaba.druid.pool.DruidDataSourceFactory;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.apache.commons.dbutils.DbUtils;

import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;

/**
 * Demo class 使用的c3p0、Druid连接技术
 *
 * @author: HuMonster
 * @date: 2020/8/10
 */
public class JDBCUtils {
  /** 使用配置文件实现c3p0连接数据库 方式二 */
  public static Connection getConnection() throws SQLException {

    ComboPooledDataSource cpds = new ComboPooledDataSource("c3p0");
    Connection conn = cpds.getConnection();
    System.out.println(conn);
    return conn;
  }

  /** 使用Druid数据库连接技术连接 方式二 */
  private static DataSource source;

  static {
    try {
      Properties props = new Properties();
      InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("druid.properties");
      props.load(is);
      source = DruidDataSourceFactory.createDataSource(props);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public static Connection getConnection2() throws Exception {
    Connection conn = source.getConnection();
    return conn;
  }

  public static void closeResourse(Connection conn, Statement ps, ResultSet rs) {

    //    /**
    //     * 第一种关闭方法
    //     */
    //    try {
    //      DbUtils.close(conn);
    //    } catch (SQLException e) {
    //      e.printStackTrace();
    //    }
    //
    //
    //    /**
    //     * 第二种关闭方法
    //     */
    //    try {
    //      if (ps != null) ps.close();
    //    } catch (Exception e) {
    //      e.printStackTrace();
    //    }
    /** 第三种关闭方法 调用dbutils.jar中提供DbUtils工具类,实现资源的关闭的方法 */
    DbUtils.closeQuietly(conn);
    DbUtils.closeQuietly(ps);
    DbUtils.closeQuietly(rs);
  }
}

c3p0-config.xml连接池的配置文件实现

<?xml version='1.0' encoding='UTF-8'?>

<c3p0-config>

    <default-config>
        <!-- 提供获取连接的4个基本信息 -->
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/~~数据库名~~ </property>
        <property name="user">~~用户名~~ </property>
        <property name="password">~~密码~~ </property>

        <!--进行数据连接池管理的基本信息 -->
        <!-- 当数据连接池中的连接数不够时,c3p0一次性向数据库申请的连接数 -->
        <property name="acquireIncrement">5</property>
        <!--c3p0数据库连接池中初始化时的连接-->
        <property name="initialPoolSize">10</property>
        <!--c3p0数据库连接池维护数最少的连接数-->
        <property name="minPoolSize">10</property>
        <!--c3p0数据库连接池维护的最多的连接数-->
        <property name="maxPoolSize">100</property>
        <!--c3p0数据库连接池维护的最多Statements的连接数-->
        <property name="maxStatements">50</property>

        <!--每个连接中可以最多使用的Statements个数-->
        <property name="maxStatementsPerConnection">5</property>
    </default-config>

    <named-config name="c3p0"></named-config>

</c3p0-config>

druid.properties 德鲁伊连接池文件配置文件(配置文件中文件信息不能留空格

username=~~数据库用户名~~ 
password=~~密码~~ 
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/info_schema
initialSize=10
maxActive=10

最后附上实现连接池的连接的多种方法(增删改查)DBUtilsConnectionTest.java

package testConnection;

import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.MapHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import org.junit.Test;

import java.sql.Connection;
import java.util.Map;

/**
 * Demo class 基于两种连接方法对数据库操作的测试
 *
 * @author: HuMonster
 * @date: 2020/8/10
 */
public class DBUtilsConnectionTest {

  /** 基于阿里提供的dbutils对数据库进行的增加操作 */
  @Test
  public void testTnsert() {
    Connection conn = null;
    try {
      QueryRunner runner = new QueryRunner();
      conn = JDBCUtils.getConnection2();
      String sql = "insert into t_admin(admin_name,admin_pwd)values(?,?)";
      int insertCount = runner.update(conn, sql, "超人1", "888");

      System.out.println("添加了" + insertCount + "条记录");
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      JDBCUtils.closeResourse(conn, null, null);
    }
  }

  /** MapHandle:是ResoultSetHandler接口的实现类,对应表中的一条记录 将字段相应的值作为map中的key和value */
  @Test
  public void testQuery() {
    Connection conn = null;
    try {
      QueryRunner runner = new QueryRunner();
      conn = JDBCUtils.getConnection2();
      String sql = "select log_amount,log_type,created from t_log where log_id = ?";

      MapHandler handler = new MapHandler();
      Map<String, Object> map = runner.query(conn, sql, handler, 50);
      System.out.println(map);
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      JDBCUtils.closeResourse(conn, null, null);
    }
  }

  /** 查询日志表的全部数据条数 c3p0 */
  @Test
  public void testQuery1() {
    Connection conn = null;
    try {
      QueryRunner runner = new QueryRunner();
      conn = JDBCUtils.getConnection();
      String sql = "select count(*) from t_log";

      ScalarHandler handler = new ScalarHandler();
      Long count = (Long) runner.query(conn, sql, handler);
      System.out.println(count);
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      JDBCUtils.closeResourse(conn, null, null);
    }
  }

  /** 查询最大数值的log—id */
  @Test
  public void testQuery2() {
    Connection conn = null;
    try {
      QueryRunner runner = new QueryRunner();
      conn = JDBCUtils.getConnection2();
      String sql = "select max(log_id) from t_log";

      ScalarHandler handler = new ScalarHandler();
      int maxId = (int) runner.query(conn, sql, handler);
      System.out.println(maxId);
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      JDBCUtils.closeResourse(conn, null, null);
    }
  }

  @Test
  public void testQuery3() {
    Connection conn = null;
    try {
      QueryRunner runner = new QueryRunner();
      conn = JDBCUtils.getConnection2();
      String sql = "select log_id,log_type,log_amount,created from t_log where log_id = ?";

      ScalarHandler handler = new ScalarHandler();
      int maxId = (int) runner.query(conn, sql, handler, 70);
      System.out.println(maxId);
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      JDBCUtils.closeResourse(conn, null, null);
    }
  }
}