使用Apache Commons Pool实现数据库连接池,apachecommons


官方示例参考:apache commons pool examples

通过组合Apache Commons Pool提供的GenericObjectPool实现数据库连接池

import org.apache.commons.pool2.PooledObjectFactory;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;

import java.io.Closeable;
import java.sql.Connection;

public class DbPool implements Closeable {
    private GenericObjectPool<Connection> internalPool;

    public DbPool(GenericObjectPoolConfig poolConfig, PooledObjectFactory factory){
        if (this.internalPool != null) {
            try {
                closeInternalPool();
            } catch (Exception e) {
            }
        }
        this.internalPool = new GenericObjectPool(factory, poolConfig);
    }

    // 获取连接
    public Connection getConnection(){
        Connection connection = null;
        try {
            connection = internalPool.borrowObject();
        } catch (Exception e) {
            throw new RuntimeException("Could not get connection from the pool", e);
        }
        return connection;
    }

    // 返还连接
    public void returnConnection(Connection connection){
        internalPool.returnObject(connection);
    }

    @Override
    public void close(){
        this.closeInternalPool();
    }

    private void closeInternalPool() {
        try {
            internalPool.close();
        } catch (Exception e) {
            throw new RuntimeException("Could not destroy the pool", e);
        }
    }
}

borrowObject的实现方式如下

public class GenericObjectPool<T> extends BaseGenericObjectPool<T>
        implements ObjectPool<T>, GenericObjectPoolMXBean, UsageTracking<T> {

    private final PooledObjectFactory<T> factory;
    private final LinkedBlockingDeque<PooledObject<T>> idleObjects;

    public T borrowObject(final long borrowMaxWaitMillis) throws Exception {
        ......
        p = idleObjects.pollFirst();
        if (p == null) {
            p = create();
            if (p != null) {
                create = true;
            }
        }
        ......
        return p.getObject();
    }
	
    private PooledObject<T> create() throws Exception {
        ......
        p = factory.makeObject(); 
        ......
        return p;
    }
}

对象池中并不直接保存最终使用的对象实例,而是使用PooledObject对最终使用的对象实例进行了一层封装

通过封装对象给对象实例增加了诸如状态、时间等一系列属性

DbConnectionFactory用来定义对象池中的对象实例的生命周期方法(创建、销毁等),通过继承Apache Commons Pool提供的BasePooledObjectFactory实现

import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;

import java.sql.Connection;
import java.sql.DriverManager;

public class DbConnectionFactory extends BasePooledObjectFactory<Connection> {

    private DbConfig dbConfig;

    public DbConnectionFactory(DbConfig dbConfig){
        super();
        this.dbConfig = dbConfig;
    }

    // 创建新的数据库连接
    public Connection create() throws Exception {
        Connection connection = DriverManager.getConnection(dbConfig.getUrl(),
                dbConfig.getUsername(), dbConfig.getPassword());
        return connection;
    }

    // 使用PooledObject对数据库连接进行包装
    public PooledObject<Connection> wrap(Connection connection) {
        return new DefaultPooledObject(connection);
    }

    // 由于validateObject失败或其它什么原因,对象实例从对象池中移除时调用
    // 不能保证对象实例被移除时所处的状态
    public void destroyObject(PooledObject<Connection> pooledConnection) throws Exception {
        Connection connection = pooledConnection.getObject();
        connection.close();
    }

    // 仅能被active状态的对象实例调用
    // 从对象池获取对象实例,在对象池返回该对象实例前,调用该方法校验其状态
    // 对象实例归还给对象池时,在调用passivateObject方法前,使用该方法校验其状态
    public boolean validateObject(PooledObject<Connection> pooledConnection) {
        Connection connection = pooledConnection.getObject();
        try {
            if (connection.isValid(1))
                return true;
            else
                return false;
        }catch(Exception e){
            return false;
        }
    }

    // 对象实例在归还给对象池时调用了passivateObject方法,通过对象池再次取到该对象实例
    // 在对象池返回该对象实例前,需要调用该方法
    public void activateObject(PooledObject<Connection> pooledConnection) throws Exception {

    }

    // 对象实例归还给对象池时调用
    public void passivateObject(PooledObject<Connection> pooledConnection) throws Exception {

    }
}

DbConfig用来保存数据库配置

public class DbConfig {

    private String url;
    private String username;
    private String password;

    public DbConfig(String driver, String url, String username,
                    String password){
        try {
            Class.forName(driver);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        this.url = url;
        this.username = username;
        this.password = password;
    }

    public String getUrl() {
        return url;
    }

    public String getUsername() {
        return username;
    }

    public String getPassword() {
        return password;
    }
}

DbPoolConfig用来保存对象池配置,通过继承Apache Commons Pool提供的GenericObjectPoolConfig实现

提供了很多对象池相关的配置属性以供使用

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;

public class DbPoolConfig extends GenericObjectPoolConfig {

    public DbPoolConfig(){
        setMaxTotal(10);
        setMaxIdle(5);
        setMinIdle(2);
    }
}

测试代码如下

import java.sql.Connection;
import java.sql.Statement;

public class Test {
    public static void main(String[] args) throws Exception {
        String driver = "com.mysql.jdbc.Driver";
        String url = "jdbc:mysql://192.168.137.128:3306/mydb";
        String username = "root";
        String password = "";

        DbConfig dbConnectionConfig = new DbConfig(
                driver, url, username, password);
        DbConnectionFactory dbConnectionFactory = new DbConnectionFactory(dbConnectionConfig);

        DbPoolConfig dbPoolConfig = new DbPoolConfig();
        dbPoolConfig.setMaxTotal(10);
        dbPoolConfig.setMaxIdle(5);
        dbPoolConfig.setMinIdle(2);
        dbPoolConfig.setMaxWaitMillis(200);
        dbPoolConfig.setTestOnBorrow(false);
        dbPoolConfig.setTestOnReturn(false);

        DbPool dbPool = new DbPool(dbPoolConfig, dbConnectionFactory);

        for(int i = 0 ; i < 20 ; i++){
            Connection connection = dbPool.getConnection();
            Statement statement = connection.createStatement();
            statement.execute("insert into t_person(name, age) values ('a', 20)");
            dbPool.returnConnection(connection);
        }
    }
}

 

相关内容

    暂无相关文章