java数据库连接池,基本设计原理

java数据库连接池

1.基本原理

​ 在内部对象池中,维护一定数量的数据库连接,并对外暴露数据库连接的获取和返回方法。如外部使用者可通过getConnection方法来获取连接,使用完毕后再同伙releaseConnection方法将连接返回,注意此时并没有关闭连接,而是由连接池管理器回收,并为下一次使用做好准备。

2.连接池的作用

1.资源重用

​ 由于数据库连接得到重用,避免了频繁的创建、释放连接引起的大量的性能开销。在减少系统消耗的基础上,增进了系统环境的平稳性(减少内存碎片以及数据库临时进程。线程的数量)

2.更快的系统响应速度

​ 数据库连接池在初始化线程过程中,往往已经创建了若干数据库连接置于线程池中备用。此时连接池的初始化操作均已完成。对于业务请求处理而言,直接利用现有可用连接,避免了数据库连接初始化和释放过程的时间开销,从而减少了系统整体响应时间。

3.新的资源分配手段

​ 对于多应用共享同一数据库的系统而言,可在应用层通过数据库连接的配置。实现数据库连接技术。

4.统一的连接管理,避免数据库连接泄露

​ 在较为完备的数据库连接池实现中,可根据预先的连接占用超时设定,强制回收被占用的连接,从而避免了常规数据库连接操作中可能出现的资源泄露。

3.基本实现思路

1.配置数据库连接池相关参数,比如数据库的连接信息,最小连接数、最大连接数等

2.初始化配置信息,创建一定数量的连接资源,并放置在一个连接池(集合),这里使用线程安全的集合来存放;

3.连接池分为两种,活跃连接池,空闲连接池,正常情况下,新来的一个连接请求,如果空闲连接池存在连接资源,直接取一个,如果不存在就新建一个。

4.如果断开某个连接,就从活跃连接池集合剔除一个,放到空闲连接池,如果空闲连接池达到了上限,即最大连接数(自定义),就关闭这个连接。

5.模拟多线程并发请求连接。

4.代码实现

1.导入jdbc驱动包

mysql,oracle都行

2.定义一个接口,获取连接和释放连接接口
package pool;
import java.sql.Connection;
public interface ConnectionService {
    //获取连接(可重复复用机制)
    public Connection getConnection();

    //回收、释放连接(可回收机制)
    public void releaseConnection(Connection connection);
}
3.配置数据库连接的基本信息,实际可以通过读取配置文件加载,这里偷懒了
package pool;

public class DbBean {
    //jdbc驱动名
    private String driverName = "oracle.jdbc.driver.OracleDriver";
    //jdbc连接URL
    private String url = "jdbc:oracle:thin:@12.15.4.241:1521:ora11g";
    //数据库用户名
    private String userName = "omonitor";
    //数据库密码
    private String password = "omonitor";
    //线程池名称
    private String poolName = "thread01";
    //空闲池,最小连接数
    private int minConnections = 1;
    //空闲池,最大连接数
    private int maxConnections = 10;
    //初始化连接数
    private int initConnections = 5;
    //重复获得连接的频率
    private long connTimeOut = 1000;
    //最大的允许连接数,和数据库设置对应
    private int maxActiveConnections = 100;
    //查看数据库设置的最大连接数
    //SELECT VALUE FROM v$parameter WHERE name='processes'    --结果为1000
    //连接超时时间,默认20分钟
    private long connectionTimeOut = 1000 * 60 * 20;

    //添加get/set方法,这里为了不占位置,就不贴出来了
}

4.连接池实现类,这里面主要是对具体方法的实现
package pool;

import java.sql.Connection;
import java.sql.DriverManager;
import java.util.List;
import java.util.Vector;

public class ConnectionPool implements ConnectionService {

    //池中没有使用的空闲线程,用Vector是因为它是线程安全的
    private List<Connection> freeConnection = new Vector<Connection>();

    //池中正在使用的线程
    private List<Connection> activeConnection = new Vector<Connection>();

    //配置文件,jdbc驱动,url,账号,密码等
    private DbBean dbBean;

    //标记创建的的连接数量
    private int countConne = 0;

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

    //初始化线程池
    public void init() {
        if (dbBean == null) {
            Exception e = new NullPointerException();
            e.printStackTrace();
        }
        //1.获取初始化连接数
        for (int i = 0; i < dbBean.getInitConnections(); i++) {
            //2.创建数据库连接
            Connection newConnection = newConnection();
            if (newConnection != null) {
                //3.存放在freeConnection集合中
                freeConnection.add(newConnection);
            }
        }
    }

    //创建Connection连接
    public synchronized Connection newConnection() {
        try {
            //加载驱动
            Class.forName(dbBean.getDriverName());
            //获取连接
            Connection connection = DriverManager.getConnection(dbBean.getUrl(), dbBean.getUserName(), dbBean.getPassword());
            //创建连接数+1
            countConne++;
            return connection;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    //连接的获取和归还,需要使用同步代码块
    @Override
    public synchronized Connection getConnection() {
        Connection connection = null;
        try {
			//判断当前创建成功的连接总数,是否达到数据库支持的最大连接数,满了使线程等待
            if (countConne < dbBean.getMaxActiveConnections()) {
                //如果空闲的连接数大于0,则直接从空闲的连接中取一个
                if (freeConnection.size() > 0) {
                	//从空闲池中获得连接
                    connection = freeConnection.get(0);
                    //拿完,记得从空闲池中删除掉,代表该连接正在使用
                    freeConnection.remove(0);
                } else {
                     //如果空闲的连接数为0,供不应求,则创建新的数据库连接
                    connection = newConnection();
                    //如果创建连接失败,发生日常,返回null,避免内存溢出
                    if(connection==null){
                        return null;
                    }
                }
                boolean available = isAvailable(connection);
                if (available) {
                    activeConnection.add(connection);
                    //countConne++;
                    
                } else {
                    countConne--;
                    connection = getConnection();
                }
            } else {
                //线程等待,connTimeOut配置的等待时间
                wait(dbBean.getConnTimeOut());
                connection = getConnection();
            }
            return connection;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    //判断连接是否可用
    public boolean isAvailable(Connection connection) {
        try {
            //如果连接为空,或者已经关闭了
            if (connection == null || connection.isClosed()) {
                return false;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;

    }

     //连接的获取和归还,需要使用同步代码块
    @Override
    public synchronized void releaseConnection(Connection connection) {
        try {
            //1.判断线程是否可用
            if (isAvailable(connection)) {
                //2.判断空闲线程是否已满
                if (freeConnection.size() < dbBean.getMaxConnections()) {
                    //空闲线程没有满,将conn加入空闲集合中
                    freeConnection.add(connection);
                } else {
                    //空闲线程满了,则关闭连接,释放资源
                    connection.close();
                    countConne--;
                }
                //将归还的连接对象从活跃的线程池中删除掉
                activeConnection.remove(connection);
                
                
                notifyAll();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }


    public static void main(String[] args) {
        //new ConnectionPool().init();
    }
}

5.用于集中管理资源的类(相当于对外的入口)
package pool;

import java.sql.Connection;

public class ConnectionPoolManager {
    //属性配置
    private static DbBean dbBean = new DbBean();

    //初始化连接数
    private static ConnectionPool connectionPool = new ConnectionPool(dbBean);

    //需要注意的是,上面的属性都是静态的,会自动加载

    //获取连接(可复用机制)
    public static Connection getConnection(){
        Connection connection = connectionPool.getConnection();
        return connection;

    }

    //释放连接(可回收机制)
    public static void releaseConnection(Connection connection){
        connectionPool.releaseConnection(connection);
    }

}

6.测试类,如何调用,以及校验正确性
package pool;

import java.sql.Connection;

public class TestConnection {
    public static void main(String[] args) {

        for (int i = 0; i < 6; i++) {
            new Thread(() -> {
                for (int j = 0; j < 10; j++) {
                    //获得conn
                    Connection connection = ConnectionPoolManager.getConnection();
                    System.out.println(Thread.currentThread().getName() + ",connection:" + connection);
                    //归还连接,不一定是关闭连接
                    ConnectionPoolManager.releaseConnection(connection);
                }
            }, "线程i获取的连接;" + i).start();
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

跳舞 D 猴子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值