4-5 数据库连接池原理

基本原理

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

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

线程池作用

 ①资源重用

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

   ②更快的系统响应速度

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

   ③新的资源分配手段

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

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

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

常用数据库连接池

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的数据源使用的就是DBCP。目前 DBCP 有两个版本分别是 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当连接数超过最大连接数时,所有连接都会被断

手写数据库连接池

读取外部配置信息

//外部配置文件信息

public class DbBean {

/* 链接属性 */

private String driverName = "com.mysql.jdbc.Driver";

 

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

 

private String userName = "root";

 

private String password = "root";

 

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

 

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

 

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

 

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

 

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

 

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

 

private long connectionTimeOut = 1000 * 60 * 20;// 连接超时时间,默认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;

}

 

}

 

创建数据库连接池

/**

 * 数据库连接池<br>

 *

 * 1.初始化<br>

 * ####线程池核心容器 空闲线程数、活动线程数<br>

 * ###构造函数 1.1.1初始化线程,存放在空闲线程池中<br>

 * 2.获取连接 <br>

 * ####1.判断存在线程数是否大于最大线程 如果大于最大线程数,则进行等待...<br>

 * ####2.判断空闲线程数是否大于0 如果空闲线程数<0,创建新的连接<br>

 * ####3.如果空闲线程数>0,则获取当前空闲线程,存入在活动线程集合中 <br>

 * 3.释放连接 <br>

 * ####3.1.1.判断空闲线程数是否大于最大线程数 <br>

 * ####3.1.2.如果空闲线程数小于最大线程数,将该连接收回到 空闲 线程集合中<br>

 * ####3.1.3.删除该连接对应的活动线程集合数据<br>

 */

public class ConnectionPool implements IConnectionPool {

 

// 空闲线程集合

private List<Connection> freeConnection = new Vector<Connection>();

// 活动线程集合

private List<Connection> activeConnection = new Vector<Connection>();

// 记录线程总数

private static int connCount = 0;

private DbBean dbBean;

 

public ConnectionPool(DbBean dbBean) {

this.dbBean = dbBean;

init();

}

 

public void init() {

try {

 

for (int i = 0; i < dbBean.getInitConnections(); i++) {

Connection newConnection = newConnection();

if (newConnection != null) {

// 添加到空闲线程中...

freeConnection.add(newConnection);

}

}

 

} catch (Exception e) {

 

}

}

 

// 创建新的Connection

private Connection newConnection() {

try {

if (dbBean == null) {

return null;

}

Class.forName(dbBean.getDriverName());

Connection connection = DriverManager.getConnection(dbBean.getUrl(), dbBean.getUserName(),

dbBean.getPassword());

connCount++;

return connection;

} catch (Exception e) {

return null;

}

 

}

 

public Connection getConnection() {

// * ####1.判断活动线程数是否大于最大线程 如果大于最大线程数,则进行等待...<br>

Connection connection = null;

try {

 

if (connCount < dbBean.getMaxActiveConnections()) {

// 还有活动线程可以使用

// * ####2.判断空闲线程数是否大于0 如果空闲线程数<0,创建新的连接<br>

if (freeConnection.size() > 0) {

connection = freeConnection.remove(0);// 等于freeConnection.get(0);freeConnection.remove(0);

} else {

// 创建新的连接

connection = newConnection();

}

 

boolean available = isAvailable(connection);

if (available) {

activeConnection.add(connection);

} else {

connCount--;// i--操作

connection = getConnection();// 递归调用getConnection方法

}

} else {

// 大于最大线程数,进行等待,重新获取连接

wait(dbBean.getConnTimeOut());

connection = getConnection();// 递归调用getConnection方法

}

} catch (Exception e) {

e.printStackTrace();

}

 

// * ####3.如果空闲线程数>0,则获取当前空闲线程,存入在活动线程集合中 <br>

return connection;

}

 

// 判断连接是否可用

public boolean isAvailable(Connection connection) {

try {

if (connection == null || connection.isClosed()) {

return false;

}

 

} catch (Exception e) {

// TODO: handle exception

}

return true;

 

}

 

public void releaseConnection(Connection connection) {

try {

if (connection == null) {

return;

}

if (isAvailable(connection)) {

// 判断空闲线程数是否大于最大线程数

if (freeConnection.size() < dbBean.getMaxConnections()) {

freeConnection.add(connection);

} else {

// 空闲线程数已经满了

connection.close();

}

activeConnection.remove(connection);

connCount--;

notifyAll();

 

}

 

} catch (Exception e) {

 

}

 

}

 

}

 

 

测试运行结果

public class Test001 {

 

public static void main(String[] args) {

 

DBThread dBThread = new DBThread();

for (int i = 1; i <= 3; i++) {

Thread thread = new Thread(dBThread, "用户线程" + i);

thread.start();

}

 

}

 

}

 

class DBThread implements Runnable {

 

public void run() {

for (int i = 0; i < 10; i++) {

Connection connection = ConnectionPoolManager.getConnection();

System.out.println(Thread.currentThread().getName() + ",connection:" + connection);

ConnectionPoolManager.releaseConnection(connection);

}

}

 

}

 

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

参与评论 您还未登录,请先 登录 后发表或查看评论
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页

打赏作者

肥嘉请求集合

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

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

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

打赏作者

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

抵扣说明:

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

余额充值