数据库连接池
1. 数据库连接池原理
在内部对象池中,维护一定数量的数据库连接,并对外暴露数据库连接的获取和返回方法。
如外部使用者可通过getConnection方法获取数据库连接,使用完毕后再通过releaseConnection方法将连接返回,注意此时的连接并没有关闭,而是由连接池管理器回收,并为下一次使用做好准备。
2. 连接池作用
- 资源重用
由于数据库连接得到重用,避免了频繁创建、释放连接引起的大量性能开销。在减少系统消耗的基础上,增进了系统环境的平稳性(减少内存碎片以级数据库临时进程、线程的数量) - 更快的系统响应速度
数据库连接池在初始化过程中,往往已经创建了若干数据库连接置于池内备用。此时连接池的初始化操作均已完成。对于业务请求处理而言,直接利用现有可用连接,避免了数据库连接初始化和释放过程的时间开销,从而缩减了系统整体响应时间。 - 新的资源分配手段
对于多应用共享同一数据库的系统而言,可在应用层通过数据库连接的配置,实现数据库连接技术。 - 统一的连接管理,避免数据库连接泄露
在较为完备的数据库连接池实现中,可根据预先的连接占用超时设定,强制收回被占用的连接,从而避免了常规数据库连接操作中可能出现的资源泄露
纯手写数据库连接池
开始之前可以回顾下jdbc的内容
倚赖仅导入驱动即可
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
- 读取外部配置信息
//外部配置文件信息
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分钟
//getter setter
}
其中较为关键的参数为空闲池数量,当有线程获取连接时,会首先判断创建的连接数是否小于maxActiveConnections ,大于线程将进行等待,小于将会从空闲池中进行取,如果能取到,则会放入活动池中,如果取不到,则新建连接,然后再放入活动池中。
释放连接时会首先判断 空闲连接池是否已满,如果已满则直接释放,如果未满则会将连接从活动池转入空闲池中
- 创建接口
//连接数据库池
public interface IConnectionPool {
// 获取连接(重复利用机制)
public Connection getConnection();
// 释放连接(可回收机制)
public void releaseConnection(Connection connection);
}
- 创建数据库连接池
/**
* ####核心参数######
* 1.空闲线程 容器 没有被使用的连接存放
* 2.活动线程 容器正在使用的连接
* ###核心步骤#####
* 1. 初始化线程池(初始化空闲线程)
* 2. 调用getConnection方法 --- 获取连接
* ## 2.1先去freeConnection获取当前连接,存放在activeConnection
* 3.调用releaseConnection方法 ----释放连接----资源回收
* ## 3.1获取activeConnection集合连接,转移到 freeConnection集合中
*/
public class ConnectionPool implements IConnectionPool {
// 使用线程安全的集合 空闲线程 容器 没有被使用的连接存放
private List<Connection> freeConnection = new Vector<Connection>();
// 使用线程安全的集合 活动线程 容器 容器正在使用的连接
private List<Connection> activeConnection = new Vector<Connection>();
private DbBean dbBean;
private static AtomicInteger countConne = new AtomicInteger();
public ConnectionPool(DbBean dbBean) {
// 获取配置文件信息
this.dbBean = dbBean;
init();
}
// 初始化线程池(初始化空闲线程)
private void init(){
if (dbBean == null) {
try {
throw new Exception("配置文件初始化失败");
} catch (Exception e) {
e.printStackTrace();
}
}
// 1.获取初始化连接数
for (int i = 0; i < dbBean.getInitConnections(); i++) {
// 2.创建Connection连接
Connection newConnection = newConnection();
if (newConnection != null) {
// 3.存放在freeConnection集合
freeConnection.add(newConnection);
}
}
}
// 创建Connection连接
private Connection newConnection() {
try {
Class.forName(dbBean.getDriverName());
Connection connection = DriverManager.getConnection(dbBean.getUrl(), dbBean.getUserName(),
dbBean.getPassword());
countConne.incrementAndGet();
return connection;
} catch (Exception e) {
return null;
}
}
// 调用getConnection方法 --- 获取连接
public Connection getConnection() {
try {
Connection connection = null;
if (countConne.get() < dbBean.getMaxActiveConnections()) {
// 小于最大活动连接数
// 1.判断空闲线程是否有数据
if (freeConnection.size() > 0) {
// 空闲线程有存在连接
// ==freeConnection.get(0);freeConnection.remove(0)
// 拿到在删除
connection = freeConnection.remove(0);
} else {
// 创建新的连接
connection = newConnection();
}
// 判断连接是否可用
boolean available = isAvailable(connection);
if (available) {
// 存放在活动线程池
activeConnection.add(connection);
} else {
countConne.decrementAndGet();
connection = getConnection();// 怎么使用重试? 递归算法
}
} else {
// 大于最大活动连接数,进行等待
wait(dbBean.getConnTimeOut());
// 重试
connection = getConnection();
}
return connection;
} catch (Exception e) {
return null;
}
}
// 判断连接是否可用
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 {
// 1.判断连接是否可用
if (isAvailable(connection)) {
// 2.判断空闲线程是否已满
if (freeConnection.size() < dbBean.getMaxConnections()) {
// 空闲线程没有满
freeConnection.add(connection);// 回收连接
} else {
// 空闲线程已经满
connection.close();
}
activeConnection.remove(connection);
countConne.decrementAndGet();
notifyAll();
}
} catch (Exception e) {
// TODO: handle exception
}
}
}
创建管理类:
// 管理线程池
public class ConnectionPoolManager {
private static DbBean dbBean = new DbBean();
private static ConnectionPool connectionPool = new ConnectionPool(dbBean);
// 获取连接(重复利用机制)
public static Connection getConnection() {
return connectionPool.getConnection();
}
// 释放连接(可回收机制)
public static void releaseConnection(Connection connection) {
connectionPool.releaseConnection(connection);
}
}
测试运行结果
public class Test01 {
public static void main(String[] args) {
ThreadConnection threadConnection = new ThreadConnection();
for (int i = 0; i < 2; i++) {
Thread thread = new Thread(threadConnection, "线程i:" + i);
thread.start();
}
}
}
class ThreadConnection implements Runnable {
public void run() {
for (int i = 0; i < 101; i++) {
Connection connection = ConnectionPoolManager.getConnection();
System.out.println(Thread.currentThread().getName() + ",connection-"+i+":" + connection);
ConnectionPoolManager.releaseConnection(connection);
}
}
}