数据库连接池,一般用于后台应用与后台数据库的交互,其目的主要是控制服务器资源消耗,常用的有Druid、C3P0、Hikari。
为了对数据库连接池有一个更深入的了解,我们手写一个简易连接池。
其具体步骤如下:
核心参数:
空闲线程数 freeConnectPool
活动线程数 activeConnectPool
原理:
1.根据配置文件参数,初始化连接池,设置初始线程数
2.通过getConnection(),获取连接,如果空闲线程大于0,则直接从空闲线程取连接,此时freeConnectPool计数减1,activeConnectPool计数加1;
否则需要判断当前线程连接是否达到最大连接数,如果达到,则wait()之后,继续调用getConnection(),
如果当前线程连接未达到最大连接数,则直接新建一个连接,并放入activeConnectPool。
3.通过releaseConnection(),释放当前连接。如果freeConnectPool已满,证明空闲线程足够多,直接关闭此连接;
如果freeConnectPool还未满,则装入空闲线程池中。
定义数据库配置POJO类:
package com.jdbc;
public class DbBean {
/* 链接属性 */
private String driverName = "com.mysql.cj.jdbc.Driver";
private String url = "jdbc:mysql://localhost:3306/test?characterEncoding=utf8&serverTimezone=UTC";
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;// 最大允许的连接数,和数据库对应
private long connectionTimeOut = 1000 * 60 * 20;// 连接超时时间,默认20分钟
}
定义连接池接口:
package com.jdbc;
import java.sql.Connection;
public interface IConnectionPool {
Connection getConnection();
void releaseConnection(Connection connection);
}
实现连接池逻辑:
package com.jdbc;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.List;
import java.util.Vector;
/*
title:手写数据库连接池
步骤:
核心参数:
空闲线程数 freeConnectPool
活动线程数 activeConnectPool
1.根据配置文件参数,初始化连接池,设置初始线程数
2.通过getConnection(),获取连接,如果空闲线程大于0,则直接从空闲线程取连接,此时freeConnectPool计数减1,activeConnectPool计数加1;
否则需要判断当前线程连接是否达到最大连接数,如果达到,则wait()之后,继续调用getConnection(),
如果当前线程连接未达到最大连接数,则直接新建一个连接,并放入activeConnectPool。
3.通过releaseConnection(),释放当前连接。如果freeConnectPool已满,证明空闲线程足够多,直接关闭此连接;
如果freeConnectPool还未满,则装入空闲线程池中。
*/
public class ConnectionPool implements IConnectionPool {
//线程安全集合
private List<Connection> freeConnectPool = new Vector<>();
private List<Connection> activeConnectPool = new Vector<>();
private DbBean dbBean;
int count = 0;//计算最大连接数
public ConnectionPool(DbBean dbBean) {
//初始化连接池
this.dbBean = dbBean;
initPool();
}
@Override
public synchronized Connection getConnection() {
//空闲线程存在空闲连接
Connection connection = null;
if (freeConnectPool.size() > 0) {
connection = freeConnectPool.remove(0);
activeConnectPool.add(connection);
} else {
//判断当前线程连接数量是否达到最大值
if (count < dbBean.getMaxActiveConnections()) {
connection = createConnection();
activeConnectPool.add(connection);
count++;
}else {
try {
wait(dbBean.getConnTimeOut());//活动线程已满等待解封
connection = getConnection();//递归调用
} catch (InterruptedException e) {
e.printStackTrace();
return null;
}
}
}
return connection;
}
@Override
public synchronized void releaseConnection(Connection connection) {
//如果空闲线程数已满,证明连接足够多
if(freeConnectPool.size() < dbBean.getMaxConnections()){
freeConnectPool.add(connection);
}else{
try {
//此时维持线程只有10个
connection.close();
activeConnectPool.remove(connection);
count--;
notifyAll();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
private void initPool() {
if (dbBean == null) {
throw new RuntimeException("配置文件为空");
}
for (int i = 0; i < dbBean.getInitConnections(); i++) {
//新建连接
Connection connection = createConnection();
if (null != connection) {
freeConnectPool.add(connection);
count++;
}
}
}
private Connection createConnection() {
/*
* 注册jdbc驱动
* */
Driver driver = null;
Connection connection = null;
try {
driver = (Driver) Class.forName(dbBean.getDriverName()).newInstance();
DriverManager.registerDriver(driver);
connection = DriverManager.getConnection(dbBean.getUrl(), dbBean.getUserName(), dbBean.getPassword());
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return connection;
}
}
管理数据库连接池:
package com.jdbc;
import java.sql.Connection;
public class ManageConnection {
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);
}
}
测试连接池:
package com.jdbc;
import java.sql.Connection;
public class TestConnection {
public static void main(String[] args) {
PoolThread poolThread = new PoolThread();
for (int i = 0; i < 5; i++) {
Thread thread = new Thread(poolThread,"线程"+i);
thread.start();
}
}
}
class PoolThread implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
Connection connection = ManageConnection.getConnection();
System.out.println("当前线程:"+Thread.currentThread().getName()+"connection: "+connection);
ManageConnection.releaseConnection(connection);
}
}
}