dbcp数据库连接池工作原理--源码系列

572 阅读3分钟

准备

pom.xml

<!-- dbcp连接池-->
<dependency>
    <groupId>commons-dbcp</groupId>
    <artifactId>commons-dbcp</artifactId>
    <version>1.4</version>
</dependency>

demo

public class DbcpUtil {
    private static DataSource dataSource = null;
    //静态代码块初始化数据库连接池
    static {
        //通过配置文件dbcp.properties 加载dbcp相关配置文件
        PropertiesUtil.load("dbcp.properties");
        try {
            //一个数据源 一个应用范围内加载一次
            dataSource = BasicDataSourceFactory.createDataSource(PropertiesUtil.getProperties());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //直接从连接池获取连接
    public static Connection getConnection() {
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return connection;
    }
public static void main(String[] args) {
    //获取连接
    Connection connection = DbcpUtil.getConnection();

    String sql1 = " select * from t_user tu where name = '张三'";
    Statement statement = null;
    try {
        statement = connection.createStatement();
        ResultSet resultSet = statement.executeQuery(sql1);
        //第四步:获取结果
        while (resultSet.next()) {
            String name = resultSet.getString("name");
            Integer age = resultSet.getInt("age");
            System.out.println("name:" + name + " age:" + age);  //打印输出结果集
        }
    } catch (SQLException e) {
        e.printStackTrace();
    }

}

到这里我们就能简单的跑一个dbcp数据库连接池的demo了

源码级原理

核心类

BasicDataSourceFactory类

BasicDataSource的工厂类,创建BasicDataSource对象,此类能查看所有数据库连接池的配置

BasicDataSource类

1、主要通过public Connection getConnection() throws SQLException方法对外提供数据库连接

2、步骤1中的getConnection()是通过内部持有的DataSource 对象提供的。后面会提到是PoolingDataSource的实例。

3、通过protected synchronized DataSource createDataSource()经过一系列处理 得到PoolingDataSource的实例

PoolingDataSource类

PoolingDataSource类持有连接池ObjectPool对象,并且通过连接池对外提供getConnection()方法。

GenericObjectPool类

上面PoolingDataSource的连接池对象,提供核心方法

//获取连接
Object borrowObject() throws Exception, NoSuchElementException, IllegalStateException;

//返回连接
void returnObject(Object obj) throws Exception;

//校验连接
void invalidateObject(Object obj) throws Exception;

//添加连接
void addObject() throws Exception, IllegalStateException, UnsupportedOperationException;

PoolableConnectionFactory类

上面GenericObjectPool类的工厂类 核心方法

//为数据库连接池提供一个连接对象
Object makeObject() throws Exception;
//为数据库连接池销毁一个连接对象
void destroyObject(Object obj) throws Exception;
//数据库连接池校验连接是否可用
boolean validateObject(Object obj);
//激活连接能够为连接池所用
void activateObject(Object obj) throws Exception;
//从连接池返回空闲状态
void passivateObject(Object obj) throws Exception;

核心流程

初始化过程

  1. 入口 加载配置 创建BasicDataSource 数据源
BasicDataSource dataSource = BasicDataSourceFactory.createDataSource(PropertiesUtil.getProperties());

这里是通过BasicDataSourceFactory工厂创建的,经过这一步的BasicDataSource实例并没有与数据库有交互,只是简单处理了一下配置项。

注意:如果需要查看dbcp支持哪些配置,这个BasicDataSourceFactory能看到每个配置项。

  1. BasicDataSource数据源赋予能力(主要是注入的datasource的能力)

image.png 展开看整个流程 忽略上面的对象不为空直接返回 image.png

2.1、加载驱动并且返回 DriverConnectionFactory 对象,该对象具有物理创建数据库连接Connection的能力 image.png 2.2、创建一个连接池 默认是GenericObjectPool类的实例 set各种properpties

image.png

2.3、创建一个PoolableConnectionFactory 并且把它注入上面连接池,为上面连接池提供make,destory数据库连接的能力

2.4、创建真实的数据源PoolingDataSource 的对象,并且PoolingDataSource持有GenericObjectPool数据库连接池对象。GenericObjectPool对象对外核心的从连接池获取,释放连接的能力。

获取连接过程

经过了上面整个初始化,现在dbcp连接池具有了对外提供数据库连接的能力。

BasicDataSource.getConnection()
-->PoolingDataSource.getConnection()
---->GenericObjectPool.borrowObject()

borrowObject流程图

borrowObject.png