一、连接池的原理。
每一次web请求都要建立一次数据库连接。建立连接需要花费大量时间,系统还要分配内存资源。对于现在的web应用,尤其是大型电子商务网站,同时有几百人甚至几千人在线是很正常的事。在这种情况下,频繁的进行数据库连接操作势必占用很多的系统资源,网站的响应速度必定下降。
其次,对于每一次数据库连接,使用完后都得断开。否则,如果程序出现异常而未能关闭,将会导致数据库系统中的内存泄漏,最终将不得不重启数据库。还有,这种开发不能控制被创建的连接对象数,系统资源会被毫无顾及的分配出去,如连接过多,也可能导致内存泄漏.
为了避免频繁的创建和断开连接,可以事先在系统中创建一定量的连接放在一个容器中,当用户需要使用时,就在池子中取出事先准备好的连接,用户使用完后,在将连接放回池子中。工作原理如下图:

代理模式实现简单连接池
实现连接池,具体需要分为两步,第一步创建自己的代理类(AgencyConnection),这个类需要继承一个Connection接口的实现类(这里采用ConnectionImpl)。同时要实现连接的回收,即需要重写Conncetion接口中colse()方法。然后这个类需要一个有参构造,用来接收原始的Connection对象,将原始的Connection对象包装成自己的代理类对象。代码如下:
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import com.mysql.jdbc.ConnectionImpl;
/**
* 代理类时connection的一个实现类 ,为了方便,继承一个connection的一个实现类
*
* @author Administrator
*
*/
public class AgencyConncetion extends ConnectionImpl {
// 定义一个Connection变量
private static Connection conn;
// 创建一个有参构造接收Connection的对象,并赋值给conn
public AgencyConncetion(Connection conn) {
this.conn = conn;
}
/**
* 重写close方法,将连接资源放到连接池中
*/
@Override
public synchronized void close() throws SQLException {
// 如果连接池中的连接数小于三,将连接回收到连接池中,否则直接调用父类的close方法,将连接断开
if (ConnPool.list.size() < 3) {
ConnPool.list.add(this);
} else {
conn.close();
}
ConnPool.maxCount++;
}
/**
* 重写prepareStatement方法,获取连接
*/
@Override
public PreparedStatement prepareStatement(String sql) throws SQLException {
//调用Connection中的方法
return conn.prepareStatement(sql);
}
}
第二步、创建连接池(ConnPool): 在这个类中,需要创建一个可以容纳连接的容器,这里使用list集合的方式。同时创建的连接对象必须是AgencyConnection类的对象,只有这样,才可以使用AgencyConncetio类中close()方法回收连接。
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
@SuppressWarnings("resource")
public class ConnPool {
// 定义池子的容量
public static int initCount = 3;
// 定义池子最大连接数
public static int maxCount = 5;
// 定义池子的容器
public static List<Connection> list = new ArrayList<Connection>();
static {
try {
// 注册驱动
Class.forName("com.mysql.jdbc.Driver");
// 创建三个连接
for (int i = 0; i < initCount; i++) {
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "root");
AgencyConncetion agency = new AgencyConncetion(conn);
list.add(agency);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 获取连接方法
*
* @return
*/
public Connection getConnection() {
// 如果池子还有连接,直接返回集合中第一个连接
if (list.size() > 0) {
// 最大连接数减一,计数
maxCount--;
return list.remove(0);
} else {
// 如果池子已经空了,而且最大连接数大于0,说明还可以继续连接
if (maxCount > 0) {
try {
// 创建临时连接并返回
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "root", "root");
return new AgencyConncetion(conn);
} catch (SQLException e) {
e.printStackTrace();
}
// 否则返回空
} else {
return null;
}
}
return null;
}
}
定义测试类,测试连接池效果
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class Test {
public static void main(String[] args) throws SQLException {
//创建连接池对象
ConnPool connPool = new ConnPool();
//调用getConnection()方法,获取连接
Connection conn1 = connPool.getConnection();
System.out.println(conn1);
Connection conn2 = connPool.getConnection();
System.out.println(conn2);
Connection conn3 = connPool.getConnection();
System.out.println(conn3);
conn1.close();
conn2.close();
conn3.close();
//关闭前三个连接
Connection conn4 = connPool.getConnection();
System.out.println(conn4);
Connection conn5 = connPool.getConnection();
System.out.println(conn5);
Connection conn6 = connPool.getConnection();
System.out.println(conn6);
Connection conn7 = connPool.getConnection();
System.out.println(conn7);
Connection conn8 = connPool.getConnection();
System.out.println(conn8);
/*
//创建操作对象
PreparedStatement ps1 = conn1.prepareStatement("insert into t_user values(null,?,?)");
//操作数据库
ps1.setString(1, "1111");
ps1.setString(2, "111222");
ps1.executeUpdate();
ps1.close();
conn1.close();
// Connection conn2 = connPool.getConnection();
// System.out.println(conn2);
// conn2.close();
*/
}
}
结果分析:连接池中定义最大的连接数是5,初始化连接数是3,前三个连接调用的是close()方法是将连接回收,放回list集合中。所以后面五个连接对应的五个地址中一定有三个与前三个连接相同。 结果如下:

代理模式中,代理类只提供了一个回收方法,Conncetion的其他功能全部都是Connection的实现类来完成。用户创建的对象却是经过包装代理类的对象。