数据库连接池实现细节

首先创建一个封装连接信息的类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();*/
	}
}

实现单线程和多线程的测试:

结果单线程始终只开启单个线程;多线程下访问线程越多占用连接也就越多

猜你喜欢

转载自blog.csdn.net/qq_38836082/article/details/81275895