时间:2021-07-01 10:21:17 帮助过:3人阅读
为了能够实现线程的循环使用,需要调用线程池的释放连接资源的方法,而不是将连接资源直接关闭。
代码如下:
1 public class TestPool { 2 // 根据配置文件里的名称创建连接池 3 private static DataPoolUtils pool = new DataPoolUtils(); 4 5 /** 6 * 主程序 7 */ 8 public static void main(String[] args) { 9 // 模拟多次对数据库的查询操作 10 for (int i = 0; i < 6; i++) { 11 new Thread(new Runnable() { 12 @Override 13 public void run() { 14 select(); 15 } 16 }, "线程" + i).start(); 17 } 18 } 19 20 /** 21 * 查询程序 22 */ 23 public static void select() { 24 Connection conn = null; 25 PreparedStatement pstmt = null; 26 ResultSet rs = null; 27 // 获取连接并执行SQL 28 try { 29 conn = pool.getConnection(); 30 pstmt = conn.prepareStatement("select * from student where id = 906"); 31 rs = pstmt.executeQuery(); 32 while (rs.next()) { 33 System.out.println(Thread.currentThread().getName() + "\t" + rs.getString(1) + "\t" + rs.getString(2) + "\t" + rs.getString("address")); 34 } 35 } catch (Exception e) { 36 e.printStackTrace(); 37 } finally { 38 // 释放资源 39 try { 40 rs.close(); 41 } catch (SQLException e) { 42 e.printStackTrace(); 43 } 44 try { 45 pstmt.close(); 46 } catch (SQLException e) { 47 e.printStackTrace(); 48 } 49 /* 50 try { 51 conn.close(); 52 } catch (SQLException e) { 53 e.printStackTrace(); 54 } 55 */ 56 pool.releaseConnection(conn); 57 } 58 } 59 }
简单的数据库连接池已经有了,但是在使用的时候如果调用了原生的关闭方法,会导致连接不能重复使用。
利用之前学过的动态代理进行改进,使调用关闭方法的时候执行的仍然是连接池里的释放资源的方法。
在 DataPoolUtils 工具类里添加动态代理的相关内部类:
1 /** 2 * 代理处理类 3 */ 4 class ConnectionInvocationHandler implements InvocationHandler{ 5 private Connection connection; 6 private DataPoolUtils dpu; 7 8 public ConnectionInvocationHandler(DataPoolUtils dpu, Connection connection) { 9 this.dpu = dpu; 10 this.connection = connection; 11 } 12 13 @Override 14 public Object invoke(Object proxy, Method method, Object[] args) 15 throws Throwable { 16 // 对原生的关闭方法进行修改 17 if(method.getName().equals("close")){ 18 dpu.releaseConnection(connection); 19 return null; 20 }else{ 21 return method.invoke(connection, args); 22 } 23 } 24 }
修改 DataPoolUtils 工具类中 public Connection getConnection() 方法的返回值,将返回值改为使用动态代理后的值:
1 return (Connection) Proxy.newProxyInstance( 2 Connection.class.getClassLoader(), 3 new Class[] { Connection.class }, 4 new ConnectionInvocationHandler(this, connection));
修改 TestPool 业务类中的 public static void select() 方法,将释放连接改为关闭连接:
1 try { 2 conn.close(); 3 } catch (SQLException e) { 4 e.printStackTrace(); 5 }
在工具类的 getConnection() 方法中返回代理类,而不是在工具类的 createConnection() 方法中返回,是因为通过后者得到的对象是要放到活动队列里的,如果在后者中返回代理对象,那么就会导致活动队列里的对象都是代理对象。
那么在执行代理对象的 close() 方法时,经过动态代理后,实际上是执行的是被代理对象的 releaseConnection() 方法,也就是将被代理对象从活动队列放到空闲队列,但因为活动队列里存放的都是代理对象,导致无法通过被代理对象从活动队列将代理对象放到空闲队列,进而导致连接资源并没有得到循环利用。
Java操作数据库——手动实现数据库连接池
标签:row timeout current 学习 pool 业务 处理 就会 ISE