首先创建一个封装连接信息的类PooledConnection;
package com.bai.pool;
import java.sql.Connection;
/**
*
* Copyright: Copyright (c) 2018 LanRu-Caifu
*
* @ClassName: PooledConnection.java
* @Description: 连接池里存放的连接信息
*
* @version: v1.0.0
* @author: Mr white
* @date: 2018年7月29日 上午11:48:10
*/
public class PooledConnection {
//数据库连接
private Connection connection;
//连接状态
private boolean isUsed;
public PooledConnection(Connection connection,boolean isUsed) {
this.connection = connection;
this.isUsed = isUsed;
}
public Connection getConnection() {
return connection;
}
//get,set方法
public void setConnection(Connection connection) {
this.connection = connection;
}
public boolean isUsed() {
return isUsed;
}
public void setUsed(boolean isUsed) {
this.isUsed = isUsed;
}
/**
* @Function: PooledConnection.java
* @Description: 放弃连接的使用
*
* @param:描述1描述
* @return:返回结果描述
* @throws:异常描述
*
* @version: v1.0.0
* @author: Mr white
* @date: 2018年7月29日 下午7:02:31
*/
public void close() {
System.out.println("归还连接使用权");
this.isUsed = false;
}
}
创建连接池的抽象类AbstractDataSourcePool规范对外的获取连接的方法getConnection():
package com.bai.pool;
/**
*
* Copyright: Copyright (c) 2018 LanRu-Caifu
*
* @ClassName: AbstractDataSourcePool.java
* @Description: 连接池抽象类
*
* @version: v1.0.0
* @author: Mr white
* @date: 2018年7月29日 上午11:49:14
*/
public abstract class AbstractDataSourcePool {
/**
*
* @Function: AbstractDataSourcePool.java
* @Description: 获取连接的方法
*
* @param:描述1描述
* @return:返回结果描述
* @throws:异常描述
*
* @version: v1.0.0
* @author: Mr white
* @date: 2018年7月29日 上午11:49:33
*/
public abstract PooledConnection getConnection();
}
实现配置文件加载器PropertiesPlaceHolder:
/**
* Copyright © 2018 eSunny Info. Tech Ltd. All rights reserved.
*
* 功能描述:
* @Package: com.bai.pool.prop
* @author: Mr white
* @date: 2018年7月29日 上午11:59:47
*/
package com.bai.pool.prop;
import java.io.InputStream;
import java.util.Properties;
/**
* Copyright: Copyright (c) 2018 LanRu-Caifu
*
* @ClassName: PropertiesPlaceHolder.java
* @Description: 读取properties的工具类
*
* @version: v1.0.0
* @author: Mr white
* @date: 2018年7月29日 上午11:59:47
*/
public class PropertiesPlaceHolder extends Properties {
private static final long serialVersionUID = 1L;
public PropertiesPlaceHolder(String properties) {
try {
InputStream in = this.getClass().getClassLoader().getResourceAsStream(properties);
//加载配置
this.load(in);
} catch (Exception e) {
e.printStackTrace();
}
}
}
配置文件jdbc.properties:
jdbc.driver.class = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://127.0.0.1:3306/ssm_ee?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false&allowPublicKeyRetrieval=true
jdbc.username = root
jdbc.password = root
initSize = 3
maxSize = 20
incrSize = 5
timeOut = 1000
编写核心连接池类DataSourcePool继承AbstractDataSourcePool:
/**
* Copyright © 2018 eSunny Info. Tech Ltd. All rights reserved.
*
* 功能描述:
* @Package: com.bai.pool
* @author: Mr white
* @date: 2018年7月29日 上午11:50:15
*/
package com.bai.pool;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.DriverManager;
import java.util.Properties;
import java.util.Vector;
import java.util.concurrent.TimeUnit;
import com.bai.pool.prop.PropertiesPlaceHolder;
/**
* Copyright: Copyright (c) 2018 LanRu-Caifu
*
* @ClassName: DataSourcePool.java
* @Description: 该类的功能描述
*
* @version: v1.0.0
* @author: Mr white
* @date: 2018年7月29日 上午11:50:15
*/
public class DataSourcePool extends AbstractDataSourcePool {
//数据库驱动名
private String driverClassName;
//数据库连接地址
private String url;
//数据库用户名
private String username;
//数据库密码
private String password;
//初始连接数量
private int initSize = 3;
//最大连接数量
private int maxSize = 20;
//连接池中当前连接使用完后还未达到最大连接数的情况,初始化的连接个数
private int incrSize = 5;
//超时时间
private int timeOut = 1000;
//轮询间隔时间毫秒
private int timeSpace = 30;
//索对象
Object lockObj = new Object();
//连接的线程安全的集合
public Vector<PooledConnection> connectionPool = new Vector<PooledConnection>();
public DataSourcePool() {
initPool();
}
/**
* @Function: DataSourcePool.java
* @Description: 该函数的功能描述
*
* @param:描述1描述
* @return:返回结果描述
* @throws:异常描述
*
* @version: v1.0.0
* @author: Mr white
* @date: 2018年7月29日 上午11:55:27
*/
private void initPool() {
//初始化读取文件的对象
Properties prop = new PropertiesPlaceHolder("jdbc.properties");
//读取配置文件信息
driverClassName = prop.getProperty("jdbc.driver.class");
url = prop.getProperty("jdbc.url");
username = prop.getProperty("jdbc.username");
password = prop.getProperty("jdbc.password");
//动态配置连接池的信息
String initSizeStr = prop.getProperty("initSize");
String maxSizeStr = prop.getProperty("maxSize");
String incrSizeStr = prop.getProperty("incrSize");
String timeOutStr = prop.getProperty("timeOut");
String timeSpaceStr = prop.getProperty("timeSpace");
initSize = initSizeStr == null ? initSize : Integer.parseInt(initSizeStr);
maxSize = maxSizeStr == null ? maxSize : Integer.parseInt(maxSizeStr);
incrSize = incrSizeStr == null ? incrSize : Integer.parseInt(incrSizeStr);
timeOut = timeOutStr == null ? timeOut : Integer.parseInt(timeOutStr);
timeSpace = timeSpaceStr == null ? timeSpace : Integer.parseInt(timeSpaceStr);
try {//把对应驱动注册到DriverManager中
Driver driver = (Driver) Class.forName(driverClassName).newInstance();
DriverManager.registerDriver(driver);
} catch (Exception e) {
}
}
/**
* @see com.bai.pool.AbstractDataSourcePool#getConnection()
* @Function: DataSourcePool.java
* @Description: 该函数的功能描述
*
* @param:描述1描述
* @return:返回结果描述
* @throws:异常描述
*
* @version: v1.0.0
* @author: Mr white
* @date: 2018年7月29日 上午11:50:15
*/
@Override
public PooledConnection getConnection() {
PooledConnection connection = null;
synchronized(lockObj) {
//连接池没有链接
if(connectionPool.size()==0) {
System.out.println("首次使用连接池,初始化连接池中的连接");
createConnections(initSize);
}
connection = getRealConnection();
//如果没有获取到连接轮询获取连接池中的对象
if(connection == null) {
while(connection == null) {
//继续创建连接
createConnections(incrSize);
connection = getRealConnection();
try {
TimeUnit.MILLISECONDS.sleep(timeSpace);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
return connection;
}
/**
* @Function: DataSourcePool.java
* @Description: 筛选出可用数据库连接
* @return:返回结果描述
* @throws:异常描述
*
* @version: v1.0.0
* @author: Mr white
* @date: 2018年7月29日 下午5:13:26
*/
private PooledConnection getRealConnection() {
//遍历连接判断是否可用
for(int i = 0; i < connectionPool.size(); i++) {
PooledConnection conn = connectionPool.get(i);
if(!conn.isUsed()) {
//获取java.sql.connection对象
Connection connection = conn.getConnection();
try {
if(!connection.isValid(timeOut)) {
connection = DriverManager.getConnection(url, username, password);
//补齐损坏的连接
conn.setConnection(connection);
}
conn.setUsed(true);
System.out.println("获取到连接对象"+conn);
return conn;
} catch (Exception e) {
e.printStackTrace();
}
}
}
return null;
}
/**
* @Function: DataSourcePool.java
* @Description: 添加连接对象到连接池
*
* @param:描述1描述
* @return:返回结果描述
* @throws:异常描述
*
* @version: v1.0.0
* @author: Mr white
* @date: 2018年7月29日 下午5:05:26
*/
private void createConnections(int initCount) {
//判断池子中的连接数<=最大连接数
if(connectionPool.size() + incrSize > maxSize) {
initCount = maxSize - connectionPool.size();
}
//船舰连接对象
for(int i = 0;i<initCount; i++) {
try {
Connection connection = DriverManager.getConnection(url, username, password);
//将连接装入对象
PooledConnection conn = new PooledConnection(connection, false);
connectionPool.add(conn);
System.out.printf("创建第%d个连接\n",connectionPool.size());
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
加入对应依赖,编写测试类:
/**
* Copyright © 2018 eSunny Info. Tech Ltd. All rights reserved.
*
* 功能描述:
* @Package: com.bai.pool
* @author: Mr white
* @date: 2018年7月29日 下午6:55:37
*/
package com.bai.pool;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
/**
* Copyright: Copyright (c) 2018 LanRu-Caifu
*
* @ClassName: Test.java
* @Description: 该类的功能描述
*
* @version: v1.0.0
* @author: Mr white
* @date: 2018年7月29日 下午6:55:37
*/
public class Test {
static DataSourcePool pool = new DataSourcePool();
public static void testConnection() {
PooledConnection connection = pool.getConnection();
PreparedStatement prep = null;
ResultSet rs = null;
try {
prep = connection.getConnection().prepareStatement("select * from sys_user");
rs = prep.executeQuery();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if(rs != null) {
rs.close();
}
if(prep != null) {
prep.close();
}
if(connection != null) {
connection.close();
}
} catch (Exception e2) {
e2.printStackTrace();
}
}
}
public static void main(String[] args) {
for(int i=0;i<10000;i++)
testConnection();
/*new Thread(new Runnable() {
@Override
public void run() {
testConnection();
}
}).start();*/
}
}
实现单线程和多线程的测试:
结果单线程始终只开启单个线程;多线程下访问线程越多占用连接也就越多