Java 数据库连接池介绍(1)--DBCP 介绍

DBCP(Database connection pooling) 是 Apache 旗下 Commons 项目下的一个子项目,提供连接池功能;本文主要介绍 DBCP 的基本使用,文中使用到的软件版本:Java 1.8.0_191、DBCP 2.9.0、Spring Boot 2.3.12.RELEASE。

1、配置参数

参数 描述
username 用户名
password 密码
url 连接 url
driverClassName 驱动名称
connectionProperties

连接属性,格式为: [propertyName=property;]*
"user" and "password" 将被除外,所以在此不需要包含这两个属性。

 

参数 默认值 描述
 defaultAutoCommit  驱动的默认值  是否自动提交
 defaultReadOnly  驱动的默认值  是否只读
 defaultTransactionIsolation  驱动的默认值

默认的事务隔离级别
NONE、READ_COMMITTED、READ_UNCOMMITTED、
REPEATABLE_READ、SERIALIZABLE

 defaultCatalog  

默认的 catalog。( 目录,类似于模式名,但比模式名更加抽象;
Oracle,MySQL 不支持,MS SQL Server = 数据库名 )

 cacheState  true  是否缓存状态信息
 defaultQueryTimeout  null  默认查询时间
 enableAutoCommitOnReturn  true  连接归还到池时,是否设置为自动提交
 rollbackOnReturn  true

如果设置为 true,则连接归还到连接池时,
如果 auto commit=true 且 read-only=false,则会自动执行一次 rollback()。

 

 参数 默认值  描述
 initialSize  0 初始连接数
 maxTotal  8 最大连接数;负数表示没有限制
 maxIdle  8 最大空闲连接数,多余的空闲连接将被释放;负数表示没有限制
 minIdle  0 最小空闲连接数,如果不足则新的空闲连接将被创建。
 maxWaitMillis  indefinitely 从连接池获取连接,最大等待时间,超过该时间将抛出异常;-1 表示无限期

 

参数 默认值 描述
validationQuery  

连接池返回连接给调用者前用来校验的查询 sql。
如果指定,则这个查询 SQL 必须至少返回一行数据;如果没有指定,则通过调用 isValid() 方法进行校验。

validationQueryTimeout no timeout 验证查询超时时间(秒)。如果设置为正数,那么通过 setQueryTimeOut() 方法来设置查询的超时时间。
testOnCreate false 连接创建后,是否验证有效性
testOnBorrow true 从连接池获取连接时,是否验证有效性
testOnReturn false 连接返回连接池时,是否验证有效性
testWhileIdle false 连接空闲时,是否验证有效性;如果验证失败,则丢弃该连接。
timeBetweenEvictionRunsMillis -1 校验空闲连接的时间周期,非正表示不验证
numTestsPerEvictionRun 3 每次校验空闲连接的个数
minEvictableIdleTimeMillis 1000 * 60 * 30 空闲连接至少多长时间后,才会被校验
softMinEvictableIdleTimeMillis -1 空闲连接至少多长时间后,才会被校验;还需满足 "空闲连接数 >=minIdle"
maxConnLifetimeMillis -1 连接存活的最大时间;如果设置为非正数,则存活时间是无限的
logExpiredConnections true 过期的连接被连接池关闭时,是否写日志
connectionInitSqls null 连接第一次创建时,执行的初始化 SQL
lifo true true 表示获取连接时将返回最后返还连接池的连接 (后进先出);false,则相反 (先进先出)。

 

参数 默认值 描述
poolPreparedStatements false 预编译语句是否池化
maxOpenPreparedStatements unlimited 最大打开的预处理语句,负数表示没有限制

 

参数 默认值 描述
accessToUnderlyingConnectionAllowed false 是否允许访问底层连接

如果允许,可以使用下面的代码来访问底层连接:

Connection conn = ds.getConnection();
Connection dconn = ((DelegatingConnection) conn).getInnermostDelegate();
...
conn.close()

 

参数 默认值 描述
removeAbandonedOnMaintenance
removeAbandonedOnBorrow
 false

是否删除泄露的连接;如果超过一个活动连接未使用的时间超过 removeAbandonedTimeout,则是一个泄露的连接。
创建 Statement,PreparedStatement,CallableStatement 或使用这些对象执行一个查询都会重置连接的上传使用时间。
removeAbandonedOnMaintenance:空闲连接校验时是否回收泄露的连接,要使启用该设置需把 timeBetweenEvictionRunsMillis 设置为整数
removeAbandonedOnBorrow:从连接池获取连接时是否回收泄露的连接,要使启用该设置还需满足 'getNumActive()> getMaxTotal() - 3 and getNumIdle() < 2'

removeAbandonedTimeout  300  连接泄露的超时时间 (秒)
logAbandoned false  连接删除时是否打印堆栈信息
abandonedUsageTracking false 如果设置为 true,数据库连接每执行一个方法都会打印堆栈信息

 

参数 默认值 描述
fastFailValidation false

是否快速失败验证;如果设置为 true,当发生致命异常时,不再执行 isValid(),也不去执行验证查询语句。致命的异常码有:
57P01 (ADMIN SHUTDOWN)
57P02 (CRASH SHUTDOWN)
57P03 (CANNOT CONNECT NOW)
01002 (SQL92 disconnect error)
JZ0C0 (Sybase disconnect error)
JZ0C1 (Sybase disconnect error)
Any SQL_STATE code that starts with "08"
要覆盖默认的异常代码,可以设置 disconnectionSqlCodes 属性。

disconnectionSqlCodes null 自定义异常代码
jmxName   注册连接池的 jmx 名称

详细的配置说明可参考官网文档:http://commons.apache.org/proper/commons-dbcp/configuration.html。

2、使用

2.1、直接使用

2.1.1、引入依赖

<dependency>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-dbcp2</artifactId>
  <version>2.9.0</version>
</dependency>

2.1.2、使用例子

package com.abc.demo.general.dbpool;

import org.apache.commons.dbcp2.BasicDataSource;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class DBCPCase {
public static void main(String[] args) {
BasicDataSource basicDataSource
= new BasicDataSource();
basicDataSource.setUrl(
"jdbc:mysql://10.49.196.11:3306/mydb?useUnicode=true&amp;characterEncoding=UTF-8");
basicDataSource.setDriverClassName(
"com.mysql.cj.jdbc.Driver");
basicDataSource.setUsername(
"root");
basicDataSource.setPassword(
"123456");
basicDataSource.setMaxTotal(
20);
basicDataSource.setMinIdle(
5);

    Connection connection </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
    Statement st </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
    ResultSet rs  </span>= <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
        connection </span>=<span style="color: rgba(0, 0, 0, 1)"> basicDataSource.getConnection();
        st </span>=<span style="color: rgba(0, 0, 0, 1)"> connection.createStatement();
        rs </span>= st.executeQuery("select version()"<span style="color: rgba(0, 0, 0, 1)">);
        </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (rs.next()) {
            System.out.println(rs.getString(</span>1<span style="color: rgba(0, 0, 0, 1)">));
        }
    } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (SQLException e) {
        e.printStackTrace();
    } </span><span style="color: rgba(0, 0, 255, 1)">finally</span><span style="color: rgba(0, 0, 0, 1)"> {
        close(connection);
    }

    </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">实际使用中一般是在应用启动时初始化数据源,应用从数据源中获取连接;并不会关闭数据源。</span>

basicDataSource.close();
}
catch (SQLException e) {
e.printStackTrace();
}
}

</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> close(Connection connection) {
    </span><span style="color: rgba(0, 0, 255, 1)">if</span> (connection != <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) {
        </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
            connection.close();
        } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (SQLException e) {
            e.printStackTrace();
        }
    }
}

}

2.2、在 SpringBoot 中使用

2.2.1、引入依赖

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.3.12.RELEASE</version>
    <relativePath />
</parent>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>

2.2.2、单数据源

application.yml 配置:

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://10.49.196.11:3306/myDb?useUnicode=true&characterEncoding=UTF-8
    username: root
    password: 123456
    type: org.apache.commons.dbcp2.BasicDataSource
    dbcp2:
      max-total: 20
      max-idle: 5

使用:

@Autowired
private DataSource dataSource;

2.2.3、多数据源

application.yml 配置:

spring:
  datasource:
    dbcp2:
      db1:
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://10.49.196.11:3306/myDb?useUnicode=true&characterEncoding=UTF-8
        username: root
        password: 123456
        max-total: 20
        max-idle: 5
      db2:
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://10.49.196.12:3306/myDb?useUnicode=true&characterEncoding=UTF-8
        username: root
        password: 123456
        max-total: 20
        max-idle: 5

数据源配置类:

package com.abc.demo.config;

import org.apache.commons.dbcp2.BasicDataSource;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

@Configuration
public class DataSourceConfig {
@Bean(
"dataSource1")
@ConfigurationProperties(prefix
= "spring.datasource.dbcp2.db1")
public DataSource dataSource1() {
return DataSourceBuilder.create().type(BasicDataSource.class).build();
}

@Bean(</span>"dataSource2"<span style="color: rgba(0, 0, 0, 1)">)
@ConfigurationProperties(prefix </span>= "spring.datasource.dbcp2.db2"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> DataSource dataSource2() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> DataSourceBuilder.create().type(BasicDataSource.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">).build();
}

}

使用:

@Autowired
@Qualifier("dataSource1")
private DataSource dataSource1;

@Autowired
@Qualifier("dataSource2")
private DataSource dataSource2;