我前几天学习了数据库连接池的基本内容,自己尝试着写了一个连接池并导出jar包使用,虽然实现了连接池的基本功能,但也存在一些问题。
以下是我连接池的目录结构:
配置文件内容:
#驱动路径
driver=com.mysql.jdbc.Driver
#JDBC连接URL
url=jdbc:mysql://127.0.0.1:3306/exercise?characterEncoding=utf8&useSSL=true
#账号
username=root
#密码
password=root
#初始连接池大小
initPoolSize=10
#最小连接数
minPoolSize=10
#最大连接数
maxPoolSize=50
#最大空闲时间
maxIdleTime=100000
#默认自动增长连接数
defaultGrow=5
连接池的三个主要实现类的代码:
package myConnectionPool;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
/**
* 连接类
* 保存单个数据库连接
* 记录该连接开始空闲时间和目前空闲时间
*/
public class WSConnection {
/**
* 数据库连接
*/
private Connection connection=null;
/**
* 开始空闲时间
*/
private long startIdleTime;
/**
* 目前空闲时间
*/
private long nowIdleTime;
/**
* 构造函数
* 获得数据库连接和该连接的开始空闲时间
*/
public WSConnection(String driver, String url, String username, String password){
try {
Class.forName(driver);
connection = DriverManager.getConnection(url, username, password);
startIdleTime=System.currentTimeMillis();
} catch (Exception e) {
System.out.println("连接获取失败!");
System.exit(0);
}
}
public WSConnection(Connection connection){
this.connection=connection;
startIdleTime=System.currentTimeMillis();
}
/**
* 提供获得数据库连接的方法
*/
public Connection getConnection() {
return connection;
}
/**
* 提供设置开始空闲时间的方法
*/
public void setStartIdleTime() {
this.startIdleTime = System.currentTimeMillis();
}
/**
* 提供获得目前空闲时间的方法
*/
public long getNowIdleTime() {
nowIdleTime=System.currentTimeMillis()-this.startIdleTime;
return nowIdleTime;
}
/**
* 提供关闭数据库连接的方法
*/
public void closeConnection(){
try {
connection.close();
} catch (SQLException e) {
System.out.println("连接关闭异常!");
System.exit(0);
}
}
}
package myConnectionPool;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.util.LinkedList;
import java.util.Properties;
/**
* 连接池类
* 管理数据库连接
*
* 实现业务逻辑:
*
* -若有用户请求连接,则将空闲连接链表的头结点从链表中移出,让用户使用
* -若有用户关闭连接,则重置该连接开始空闲时间,并将其加入空闲连接链表队尾
*
* -没有空闲连接时,主动创建一定数目空闲连接,但要保证总连接数不超过最大连接数
* -当总连接数小于最小连接数时,主动创建一定数目空闲连接,保证总连接数不超过最大连接数
*
* -当总连接数大于最大连接数时,关闭空闲连接
* -当连接的目前空闲时间大于最大空闲时间时,关闭该连接
*
* -当连接池已满,仍有用户请求连接时,先让其等待最大空闲时间,如果之后连接池仍然无空闲连接时,报告获取连接失败,请稍后重试错误
*/
public class WSConnectionPool {
/**
*属性1:驱动路径,从配置文件获取
*/
private String driver;
/**
*属性2:DBC连接URL,从配置文件获取
*/
private String url;
/**
*属性3:数据库账号,从配置文件获取
*/
private String username;
/**
*属性4:数据库密码,从配置文件获取
*/
private String password;
/**
*属性5:初始数据库连接数,从配置文件获取
*/
private int initPoolSize;
/**
*属性6:最小数据库连接数,从配置文件获取
*/
private int minPoolSize;
/**
*属性7:最大数据库连接数,从配置文件获取
*/
private int maxPoolSize;
/**
*属性8:数据库连接最大空闲时间,从配置文件获取
*/
private int maxIdleTime;
/**
*属性9:目前的数据库连接数(包括空闲数据库连接和已分配数据库连接)
*/
private int nowPoolSize=0;
/**
*属性10:数据库空闲连接的集合,LinkedList集合:add()尾插返回Boolean,pop()头删返回Connection
*/
private LinkedList pool= new LinkedList ();
/**
*属性11:默认自动增长连接数,从配置文件获取
*/
private int defaultGrow;
/**
* 构造方法,为11个属性设置初始值
*/
public WSConnectionPool(){
try {
/**
* 加载配置文件
*/
Properties properties = new Properties();
InputStream resourceAsStream =WSConnectionPool.class.getClassLoader().getResourceAsStream("wsConnectionPool.properties");
properties.load(resourceAsStream);
/**
* 从配置文件中读取相关属性值
*/
driver=properties.getProperty("driver");
url=properties.getProperty("url");
username=properties.getProperty("username");
password=properties.getProperty("password");
initPoolSize=Integer.parseInt(properties.getProperty("initPoolSize"));
minPoolSize=Integer.parseInt(properties.getProperty("minPoolSize"));
maxPoolSize=Integer.parseInt(properties.getProperty("maxPoolSize"));
maxIdleTime=Integer.parseInt(properties.getProperty("maxIdleTime"));
defaultGrow= Integer.parseInt(properties.getProperty("defaultGrow"));
/**
* 数据库连接池初始化配置检查
*/
/**
* 1.检查最大空闲时间是否大于零
*/
if(maxIdleTime<=0){
throw new Exception();
}
/**
* 2.检查最小连接数是否小于等于最大连接数
*/
if(minPoolSize>maxPoolSize){
throw new Exception();
}
/**
* 3.检查初始连接数是否小于等于最大连接数,是否大于等于最小连接数
*/
if(initPoolSizemaxPoolSize){
throw new Exception();
}
/**
* 根据从配置文件中得到的属性值设置其他属性:
* 创建初始连接数个数据库连接,并更新目前的数据库连接数
*/
growConnection(initPoolSize);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
System.out.println("配置信息错误,连接池初始化失败!");
System.exit(0);
}
}
/**
* 创建一定数目的空闲连接的方法
*/
/**
* 创建一个空闲连接
*/
private void growConnection(){
WSConnection wsConnection = new WSConnection(driver, url, username, password);
pool.add(wsConnection);
addNowConnection();
}
/**
* 创建指定数目的空闲连接
*/
private void growConnection(int time){
for (int i = 0; i < time; i++) {
growConnection();
}
}
/**
* 连接池关闭连接的方法
*/
/**
* 关闭指定的数据库连接
*/
private void closeConnection(WSConnection wsConnection){
wsConnection.closeConnection();
deleteNowConnection();
}
/**
* 检查空闲连接链表,查找目前空闲时间大于最大空闲时间的连接并关闭
*/
private void closeIdleConnection(){
WSConnection wsConnection=null;
for (int i = 0; i < pool.size(); i++) {
wsConnection=pool.get(i);
if(wsConnection.getNowIdleTime()>maxIdleTime){
pool.remove(i);
i--;
closeConnection(wsConnection);
}
}
}
/**
* 关闭已分配给用户的连接(实际上是将该连接尾插入空闲连接链表,并重置该连接的开始空闲时间)
*/
private void closeUsingConnection(WSConnection wsConnection){
pool.add(wsConnection);
wsConnection.setStartIdleTime();
}
/**
* 处理目前连接数和空闲连接数的方法
*/
/**
* 增加目前连接数,如果目前连接数大于最大连接数,释放连接
*/
private void addNowConnection(){
nowPoolSize++;
while(nowPoolSize>maxPoolSize){
closeIdleConnection();
}
}
/**
* 减少目前连接数,如果目前连接数小于最小连接数,建立自动增长连接数个空闲连接
*/
private void deleteNowConnection(){
nowPoolSize--;
if(nowPoolSize
package myConnectionPool;
import java.sql.Connection;
/**
* 连接池管理类
* 含有唯一的连接池类
* 只负责连接的获取和释放
*/
public class WSConnectionPoolManage {
/**
* 唯一的连接池类
*/
private static WSConnectionPool connectionPool=new WSConnectionPool();
/**
* 获取数据库连接的方法
*/
public static synchronized Connection getConnection() {
return connectionPool.getConnection();
}
/**
* 释放数据库连接的方法
*/
public static synchronized void releaseConnection(Connection connection) {
connectionPool.releaseConnection(connection);
}
/**
* 主方法
*/
public static void main(String[] args) {
WSConnectionPoolManage connectionPoolManage = new WSConnectionPoolManage();
System.out.println("连接池创建成功!");
}
}
jar包使用测试:
jar包执行测试:
一个客户连接测试:
多个客户连接测试:
测试代码:
测试结果:
大量测试结果分析:
当连接用户数目较少时,所有用户均可获取连接,但用户数目较大时,有些用户无法获取连接。
该连接池存在问题:
1.配置文件信息在jar包中固定了,使用jar包时不能修改,使得jar包通用性不强。
2.用户获取和释放连接方法均加了锁,使得连接池并发度不高。
3.在目前数据库连接数发生变化时才进行连接池维护,不能自动维护连接池。