关闭连接池的方法就是将连接放回连接池,会另外创建一个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(); } } } }
测试