手写数据库连接池

本文深入解析数据库连接池的工作原理,探讨其如何通过资源重用提升系统响应速度,降低内存消耗,以及避免数据库连接泄露。同时,对比分析了C3P0、BoneCP、DBCP等主流连接池的特性及适用场景。
配置数据库连接池的参数

空闲线程数(初始化线程,还没有被使用) 2
活动线程数(正在被使用线程) 3
最大线程数(限制最多可创建) 7
空闲线程已经全部被使用,最多实际可用多少个线程 2 + 3 = 5

基本原理

在内部对象池中,维护一定数量的数据库连接,并对外暴露数据库连接的获取和返回方法。

如外部使用者可通过getConnection方法获取数据库连接,使用完毕后再通过releaseConnection方法将连接返回,注意此时的连接并没有关闭,而是由连接池管理器回收,并为下一次使用做好准备。

数据库连接池作用
  1. 资源重用
    由于数据库连接得到重用,避免了频繁创建、释放连接引起的大量性能开销。在减少系统消耗的基础上,增进了系统环境的平稳性(减少内存碎片以级数据库临时进程、线程的数量)
  2. 更快的系统响应速度
    数据库连接池在初始化过程中,往往已经创建了若干数据库连接置于池内备用。此时连接池的初始化操作均已完成。对于业务请求处理而言,直接利用现有可用连接,避免了数据库连接初始化和释放过程的时间开销,从而缩减了系统整体响应时间。
  3. 新的资源分配手段
    对于多应用共享同一数据库的系统而言,可在应用层通过数据库连接的配置,实现数据库连接技术。
  4. 统一的连接管理,避免数据库连接泄露
    在较为完备的数据库连接池实现中,可根据预先的连接占用超时设定,强制收回被占用的连接,从而避免了常规数据库连接操作中可能出现的资源泄露
常用数据库连接池
C3P0

C3P0是一个开放源代码的JDBC连接池,它在lib目录中与Hibernate一起发布,包括了实现jdbc3和jdbc2扩展规范说明的Connection 和Statement 池的DataSources 对象。

BoneCP

BoneCP 是一个开源的快速的 JDBC 连接池。BoneCP很小,只有四十几K(运行时需要log4j和Google Collections的支持,这二者加起来就不小了),而相比之下 C3P0 要六百多K。另外个人觉得 BoneCP 有个缺点是,JDBC驱动的加载是在连接池之外的,这样在一些应用服务器的配置上就不够灵活。当然,体积小并不是 BoneCP 优秀的原因,BoneCP 到底有什么突出的地方呢,请看看性能测试报告。Tomcat的数据源使用的就是BoneCP 。目前 BoneCP 有两个版本分别是 1.3 和 1.4。1.3 版

DBCP

DBCP (Database Connection Pool)是一个依赖Jakarta commons-pool对象池机制的数据库连接本对应的是 JDK 1.4-1.5 和 JDBC 3,而1.4 版本对应 JDK 1.6 和 JDBC 4。因此在选择版本的时候要看看你用的是什么 JDK 版本了,功能上倒是没有什么区别。

Proxool

Proxool是一个Java SQL Driver驱动程序,提供了对你选择的其它类型的驱动程序的连接池封装。可以非常简单的移植到现存的代码中。完全可配置。快速,成熟,健壮。可以透明地为你现存的JDBC驱动程序增加连接池功能。

DBCP与C3P0区别

dbcp没有自动的去回收空闲连接的功能 c3p0有自动回收空闲连接功能 两者主要是对数据连接的处理方式不同!C3P0提供最大空闲时间,DBCP提供最大连接数。 前者当连接超过最大空闲连接时间时,当前连接就会被断掉。DBCP当连接数超过最大连接数时,所有连接都会被断

手写数据库连接池实现
核心参数
  1. 空闲连接(空闲线程):容器没有被使用的连接存放
  2. 活动线程:容器正在使用的连接
读取外部配置信息
/**
 * 外部配置信息
 */
public class DbBean {

    /**
     * 链接属性
     */
    private String driverName = "com.mysql.jdbc.Driver";

    private String url = "jdbc:mysql://47.102.136.26:3306/test";

    private String userName = "root";

    private String password = "123456";

    /**
     * 连接池名字
     */
    private String poolName = "thread01";

    /**
     * 空闲池,最小连接数
     */
    private int minConnections = 1;

    /**
     * 空闲池,最大连接数
     */
    private int maxConnections = 10;

    /**
     * 初始化连接数
     */
    private int initConnections = 5;

    /**
     * 重复获得连接的频率
     */
    private long connTimeOut = 1000;

    /**
     * 最大允许的连接数,和数据库对应
     */
    private int maxActiveConnections = 100;

    /**
     * 连接超时时间,默认20分钟
     */
    private long connectionTimeOut = 1000 * 60 * 20;

    public String getDriverName() {
        return driverName;
    }

    public void setDriverName(String driverName) {
        this.driverName = driverName;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getPoolName() {
        return poolName;
    }

    public void setPoolName(String poolName) {
        this.poolName = poolName;
    }

    public int getMinConnections() {
        return minConnections;
    }

    public void setMinConnections(int minConnections) {
        this.minConnections = minConnections;
    }

    public int getMaxConnections() {
        return maxConnections;
    }

    public void setMaxConnections(int maxConnections) {
        this.maxConnections = maxConnections;
    }

    public int getInitConnections() {
        return initConnections;
    }

    public void setInitConnections(int initConnections) {
        this.initConnections = initConnections;
    }

    public long getConnTimeOut() {
        return connTimeOut;
    }

    public void setConnTimeOut(long connTimeOut) {
        this.connTimeOut = connTimeOut;
    }

    public int getMaxActiveConnections() {
        return maxActiveConnections;
    }

    public void setMaxActiveConnections(int maxActiveConnections) {
        this.maxActiveConnections = maxActiveConnections;
    }

    public long getConnectionTimeOut() {
        return connectionTimeOut;
    }

    public void setConnectionTimeOut(long connectionTimeOut) {
        this.connectionTimeOut = connectionTimeOut;
    }
}
创建数据库连接池
public class ConnectionPool implements IConnectionPool {

    /**
     * 空闲线程集合
     */
    private List<Connection> freeConnection = new Vector<>();

    /**
     * 活动线程集合
     */
    private List<Connection> activeConnection = new Vector<>();

    private DbBean dbBean;

    private AtomicInteger countConne = new AtomicInteger();

    public ConnectionPool(DbBean dbBean)  {
        this.dbBean = dbBean;
        init();
    }

    /**
     * 初始化线程池(初始化空闲线程)
     */
    private void init() {
        if (dbBean == null){
            return;
        }
        //1.获取初始化连接数
        for (int i = 0; i < dbBean.getInitConnections(); i++) {
            //2.创建Connection连接
            Connection connection = createConnection();
            //3.存放在freeConnection集合
            freeConnection.add(connection);
        }

    }

    /**
     * 创建Connection连接
     * @return
     */
    private Connection createConnection(){
        try {
            Class.forName(dbBean.getDriverName());
            Connection connection = DriverManager.getConnection(dbBean.getUrl(), dbBean.getUserName(), dbBean.getPassword());
            countConne.incrementAndGet();
            return connection;
        } catch (Exception e) {
            return null;
        }
    }

    @Override
    public synchronized Connection getConnection() {
        //当前创建的连接>最大连接数
        Connection connection = null;
        if (countConne.get() < dbBean.getMaxActiveConnections()){
            //小于最大活动连接数
            //1.判断空闲线程是否有数据
            if (freeConnection.size() > 0 ){
                //空闲线程有存在连接
                //拿到再删除
                connection = freeConnection.remove(0);
            }else{
                //创建新连接
                connection = createConnection();
            }
            boolean available = isAvailable(connection);
            if (available){
                //存放在活动连接池
                activeConnection.add(connection);
            }else{
                countConne.decrementAndGet();
                connection = getConnection();
            }
        }else{
            //大于最大活动连接数 等待重复获得连接的频率后 重试
            try {
                wait(dbBean.getConnTimeOut());
                connection = getConnection();
            } catch (InterruptedException e) {
                return null;
            }
        }
        return connection;
    }

    private boolean isAvailable(Connection connection){
        try {
            if (connection == null || connection.isClosed()){
                return false;
            }
        } catch (SQLException e) {
            return false;
        }
        return true;
    }

    @Override
    public synchronized void releaseConnection(Connection connection)  {
        //判断线程是否可用
        if (isAvailable(connection)){
            //判断空闲线程是否大于活动线程
            if (freeConnection.size() < dbBean.getMaxConnections()){
                //空闲线程没有满
                freeConnection.add(connection);
            } else{
                //空闲线程已满
                try {
                    connection.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            activeConnection.remove(connection);
            countConne.decrementAndGet();
            notifyAll();
        }
    }
}
管理数据库连接池
public class ConnectionPoolManager {

    private static DbBean dbBean = new DbBean();
    private static ConnectionPool connectionPool = new ConnectionPool(dbBean);

    /**
     * 获取连接(可重复利用机制)
     * @return
     */
    public static   Connection getConnection(){
        return connectionPool.getConnection();
    }

    /**
     * 释放连接(回收机制)
     * @return
     */
    public static void releaseConnection(Connection connection){
        connectionPool.releaseConnection(connection);
    }
}
测试运行结果
public class Test {
    public static void main(String[] args) {
        ThreadConnectoin threadConnectoin = new ThreadConnectoin();
        for (int i = 0; i < 3; i++) {
            Thread thread = new Thread(threadConnectoin, "线程i:" + i);
            thread.start();
        }
    }
}

class ThreadConnectoin implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            Connection connection = ConnectionPoolManager.getConnection();
            System.out.println(Thread.currentThread().getName() + ":" + connection);
            ConnectionPoolManager.releaseConnection(connection);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值