关闭连接池的方法就是将连接放回连接池,会另外创建一个free方法把连接放回集合中,但是,如果操作直接关闭原来的connection而不是使用定义的方法,就容易造成连接池失效。
所以,必须要拦截关闭原来连接的close方法。这种方法是代理模式的一种(不是很了解)
》》通过实现jdbc.connection接口
实际上真正的连接的其他工作交给真正的sql的connection去做,我们要做的是实现接口(jdbc)里的close方法。
如下
package com.yiki.pool;
import java.sql.Array;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.NClob;
import java.sql.PreparedStatement;
import java.sql.SQLClientInfoException;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.SQLXML;
import java.sql.Savepoint;
import java.sql.Statement;
import java.sql.Struct;
import java.util.Map;
import java.util.Properties;
import java.util.TimeZone;
import java.util.concurrent.Executor;
import com.mysql.jdbc.ExceptionInterceptor;
import com.mysql.jdbc.Extension;
import com.mysql.jdbc.MySQLConnection;
import com.mysql.jdbc.log.Log;
public class myConnection implements com.mysql.jdbc.Connection {// Jdbc的connection
private Connection realConnection;// sql的connection
private myDataSource dataSource;
public myConnection(Connection connection, myDataSource dataSource) {
this.realConnection = connection;
this.dataSource = dataSource;
}
@Override
public void close() throws SQLException {// 最重要的!!!!!!
this.dataSource.conPool.addLast(this);
}
@Override
public Statement createStatement() throws SQLException {
return this.realConnection.createStatement();
}
@Override
public PreparedStatement prepareStatement(String sql) throws SQLException {
return this.realConnection.prepareStatement(sql);
}
//...以下省略n个要实现的方法……方式同上
但是:你会发现如果要把除了close的方法其他方法都要return this.realConnection.方法,就会发现非常繁琐
package com.yiki.pool;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.LinkedList;
public class myDataSource {
private static String url;
private static String user;
private static String password;
private static int initSize = 3;// 初始化连接池的连接数
private static int MaxSize = 5;// 假设数据库可以创建的最大连接数
private static int CurrentSize = 0;// 当前连接数
static {
url = "jdbc:mysql://localhost:3306/yiki?useUnicode=true&characterEncoding=gb2312";
user = "root";
password = "******";
}
LinkedList<Connection> conPool = new LinkedList<Connection>();// 创建链表来存储连接
public myDataSource() {
for (int i = 0; i < initSize; i++) {// 连接池可以容纳5个连接
try {
this.conPool.addLast(this.createCon());
myDataSource.CurrentSize++;
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public Connection getCon() throws Exception {
synchronized (conPool) {// 加锁,保证多个线程不会难道同一个链接
if (this.conPool.size() > 0) {// 看看还有没有
return this.conPool.removeFirst();// 就是从连接池里取出来(连接池是链表,移走表头
} // else表已经没有连接了,就再创建连接
if (myDataSource.CurrentSize < MaxSize) {// 如果请求的连接超载了,可在数据库允许的连接上再创建连接
myDataSource.CurrentSize++;
return this.createCon();
}
throw new SQLException("连接池已没有链接");
}
}
public void free(Connection con) {// 释放连接就是把连接放回连接池
if (con instanceof myConnection) {
this.conPool.addLast((myConnection)con);
}
}
private Connection createCon() throws SQLException {// 创建连接
Connection realConn = DriverManager.getConnection(url, user, password);
myConnection myConnection = new myConnection(realConn, this);//拦截close,防止其他人把真正的connection关掉,而是把它添加回连接池
return myConnection;
}
}
》》动态代理实现InvocationHandler接口
package com.yiki.ConnHandler;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
public class myConnectionHandler implements InvocationHandler {
private Connection realConnection;// sql
private myDataSource dataSource;
private Connection warpedConnection;
private int maxUseCount = 10;// 最大连接次数
private int currentUserCount = 0;// 现在连接次数
myConnectionHandler(myDataSource myDataSource) {
this.dataSource = myDataSource;
}
Connection bind(Connection realconn) {
this.realConnection = realconn;
this.warpedConnection = (Connection) Proxy.newProxyInstance(this.getClass().getClassLoader(),
new Class[] { Connection.class }, this);
return warpedConnection;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ("close".equals(method.getName())) {
this.currentUserCount++;
if (currentUserCount < maxUseCount) {
this.dataSource.conPool.addLast(this.warpedConnection);
} else {
this.realConnection.close();
myDataSource.CurrentSize--;
System.out.println("myDataSource.CurrentSize:"+myDataSource.CurrentSize);
}
}
return method.invoke(this.realConnection, args);
}
}
package com.yiki.ConnHandler;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.LinkedList;
public class myDataSource {
private static String url;
private static String user;
private static String password;
private static int initSize = 3;// 初始化连接池的连接数
private static int MaxSize =10;// 假设数据库可以创建10个连接
public static int CurrentSize = 0;// 当前连接数
static {
url = "jdbc:mysql://localhost:3306/yiki?useUnicode=true&characterEncoding=gb2312";
user = "root";
password = "******";
}
LinkedList<Connection> conPool = new LinkedList<Connection>();// 创建链表来存储连接
public myDataSource() {
for (int i = 0; i < initSize; i++) {// 连接池可以容纳5个连接
try {
this.conPool.addLast(this.createCon());
myDataSource.CurrentSize++;
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public Connection getCon() throws Exception {
synchronized (conPool) {// 加锁,保证多个线程不会难道同一个链接
if (this.conPool.size() > 0) {// 看看还有没有
return this.conPool.removeFirst();// 就是从连接池里取出来(连接池是链表,移走表头
} // else表已经没有连接了,就再创建连接
if (myDataSource.CurrentSize < MaxSize) {// 如果请求的连接超载了,可在数据库允许的连接上再创建连接
myDataSource.CurrentSize++;
return this.createCon();
}
throw new SQLException("连接池已没有链接");
}
}
public void free(Connection con) {// 释放连接就是把连接放回连接池
this.conPool.addLast(con);
}
private Connection createCon() throws SQLException {// 创建连接
Connection realconn = DriverManager.getConnection(url, user, password);
myConnectionHandler proxy = new myConnectionHandler(this);
return proxy.bind(realconn);
}
}
package com.yiki.ConnHandler;
import java.sql.Connection;
public class DButil {
private static String driver;
private static myDataSource source ;
static {
driver = "com.mysql.jdbc.Driver";
source = new myDataSource();
}
public static Connection open() {
try {
Class.forName(driver);
return source.getCon();
} catch (Exception e) {
e.printStackTrace();
System.out.println("连接错误");
}
return null;
}
public static void close(Connection con) {
if (con != null) {
try {
con.close();
//source.free(con);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
测试