关于使用数据库连接池的好处以及数据库连接池要解决的问题我就不在赘述了,网上有很多文章说明,本文主要是通过模拟数据库连接池的实现,因为我所在单位使用的数据库类型为DB2,所以这里以DB2为例,其他类型数据库也类似
实现一个数据库连接池,其实主要关注这三个对象:1.连接对象2.连接池对象3.策略
上代码:
1.接口类
package DataSourcePool;
import java.sql.Connection;
/**
* <p>创建人:刘星 创建日期:2017-3-7 下午6:13:53</p>
* <p>功能描述:(数据库连接池接口)</p>
* @version V1.0
*/
public interface InterfaceDataSourcePool {
//获取链接
public Connection getConnectionFromPool();
//释放链接
public void releaseConnection(Connection connection);
//判断连接池是否有资源
public boolean isDataSourcePoolActive();
}
2.连接池实现类
package DataSourcePool;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.LinkedList;
import com.ibm.db2.jcc.DB2Driver;
/**
* <p>创建人:刘星 创建日期:2017-3-7 下午6:05:34</p>
* <p>功能描述:(数据源资源池实现类)</p>
* @version V1.0
*/
public class DataSourcePool implements InterfaceDataSourcePool{
public static LinkedList<Connection> dataSourcePool= new LinkedList<Connection>();//初始化链表,用来存储连接
private volatile static int initPoolSize = 10;//初始化连接池大小
private volatile static int maxActiveAlive = 15;//连接池最大存活连接数
private volatile static int minActiveAlive = 15;//连接池最小存活连接数
private volatile static int isActiveOn = 0;//连接池当前存活连接数
/**
* <p>创建人: 刘星 创建日期:2017-3-8下午1:03:35</p>
* <p>功能描述:(重写构造函数)</p>
* @param 对方法中某参数的说明
* @exception 对方法可能抛出的异常进行说明
* @version 1.0
*/
public DataSourcePool(){
System.out.println("初始化数据库连接池");
initDataSourcePool();//初始化连接池,创建指定个数的链接到资源池中
}
/**
* <p>创建人:刘星 创建日期:2017-3-8下午1:17:12</p>
* <p>功能描述:(初始化连接池)</p>
* @param 对方法中某参数的说明
* @return 对方法返回值的说明
* @exception 对方法可能抛出的异常进行说明
* @version 1.0
*/
public void initDataSourcePool(){
System.out.println("将创建数据库连接到池中");
try{
for(int i = 0; i <initPoolSize; i++){
addConnection();//添加链接到资源池操作
}
}catch(Exception e){
e.printStackTrace();
}
}
/**
* <p>创建人:刘星 创建日期:2017-3-8下午1:09:21</p>
* <p>功能描述:(添加连接到资源池)</p>
* @param 对方法中某参数的说明
* @return 对方法返回值的说明
* @exception 对方法可能抛出的异常进行说明
* @version 1.0
*/
public void addConnection(){
try{
isActiveOn++;//当前存活连接数+1
if(maxActiveAlive < isActiveOn-1){//如果最大允许连接数大于+1前的存活连接数,则不再新建连接
return;
}
DriverManager.registerDriver(new DB2Driver());
//通过JDBC建立数据库连接 ,我这里用的是DB2数据库,可根据数据库类型自行配置
Connection con =DriverManager.getConnection(
"jdbc:db2://IP:PORT", "userName", "password");
dataSourcePool.add(con);//将连接放入资源池中
}catch(Exception e){
e.printStackTrace();
}
}
/**
* <p>功能描述:(获取一个连接从连接池中)</p>
* @param 对方法中某参数的说明
* @return 对方法返回值的说明
* @exception 对方法可能抛出的异常进行说明
* @version 1.0
*/
@Override
public Connection getConnectionFromPool() {
Connection con = null;
//首先判断连接池是否为空,若不为空,则从队列中取出队首,同时存活连接数-1
if(!dataSourcePool.isEmpty() && dataSourcePool.size()>0){
con = dataSourcePool.removeFirst();
isActiveOn--;
}else{
//若为空,根据各自不同业务逻辑自行处理
System.out.println("当前连接池为空:");
return null;
}
//判断当前连接数是否小于允许最小连接数。如果小于则向资源池中新增差值个链接
if(minActiveAlive > isActiveOn){
while(minActiveAlive-isActiveOn>0){
addConnection();
}
}
if(con == null){
System.out.println("获取到当前的连接对象为空:"+con);
}
return con;
}
/**
* <p>功能描述:(释放一个连接,将连接归还给连接队列)</p>
* @param 对方法中某参数的说明
* @return 对方法返回值的说明
* @exception 对方法可能抛出的异常进行说明
* @see 父类方法:package.Class#method(Type, Type,...)
* @version 1.0
*/
@Override
public void releaseConnection(Connection connection) {
if(connection == null){
System.out.println("获取到当前的连接对象为空:"+connection);
}
dataSourcePool.add(connection);
}
/**
* <p>创建人:刘星 创建日期:2017-3-7 下午6:17:36</p>
* <p>功能描述:(判断当前资源池中是否有存活的链接数)</p>
* @param 对方法中某参数的说明
* @return 对方法返回值的说明
* @exception 对方法可能抛出的异常进行说明
* @version 1.0
*/
@Override
public boolean isDataSourcePoolActive() {
boolean flag = false;
if(isActiveOn > 0){
flag= true;
}
return flag;
}
}
3.测试类实现
public static void main(String args[]){
DataSourcePool pool = new DataSourcePool();
Connection con = pool.getConnectionFromPool();
System.out.println("获取到的链接对象为:"+con.toString());//jdksql中connection并未重写toString方法,所以这里输出的是链接对象所在的内存地址
try{
Statement statement = con.createStatement();
con.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);//设置事务级别为读提交
ResultSet result = statement.executeQuery("select * from table");//这里写执行的sql语句
while(result.next()){
System.out.println(result.getString("id"));
}
}catch(Exception e){
e.printStackTrace();
}finally{
}
}
部分输出:
初始化数据库连接池
将创建数据库连接到池中
获取到的链接对象为:com.ibm.db2.jcc.t4.b@75baf976
2017030000001336
2017030000001334
2017030000001333
2017030000001331
4.总结
在本文中仅仅实现了静态策略设置最小连接数、最大连接数、初始默认连接数。动态即每隔一定时间就对连接池进行检测,如果发现连接数量小于最小连接数,则补充相应数量的新连接以保证连接池的正常运转。
现在网上有很多开源的数据库连接池,如
Apache commons-dbcp 连接池(:http://commons.apache.org/proper/commons-dbcp/)
c3p0 连接池(http://sourceforge.net/projects/c3p0/)
druid 连接池(阿里开源)
这些都是很成熟并且高效的开源实现,策略更加完备。其实只要明白其中缘由即可,无需把每种策略都实现一遍。