对于共享资源,有一个很著名的设计模式:资源池(Resource Pool)。该模式正是为了解决资源的频繁分配﹑释放所造成的问题。为解决我们的问题,可以采用数据库连接池技术。数据库连接池的基本思想就是为数据库连接建立一个“缓冲池”。预先在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从“缓冲池”中取出一个,使用完毕之后再放回去。我们可以通过设定连接池最大连接数来防止系统无尽的与数据库连接。更为重要的是我们可以通过连接池的管理机制监视数据库的连接的数量﹑使用情况,为系统开发﹑测试及性能调整提供依据。
数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现的尤为突出。对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标。数据库连接池负责分配,管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个。
以下是传统的链接方式和连接池的对比:
现在可以自己做一个实例,写一个连接池的测验
假定现在连接池的最大上限是6个,初始化的连接池中有三个,可以按以下步骤完成代码
自定义连接池, 管理连接
代码实现:
1. MyPool.java 连接池类,
2. 指定全局参数: 初始化数目、最大连接数、当前连接、 连接池集合
3. 构造函数:循环创建3个连接
4. 写一个创建连接的方法
5. 获取连接
------> 判断: 池中有连接, 直接拿
------> 池中没有连接,
------> 判断,是否达到最大连接数; 达到,抛出异常;没有达到最大连接数,
创建新的连接
6. 释放连接
-------> 连接放回集合中(..)
package com.connectionPool; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.util.LinkedList; /** * 自定义连接池, 管理连接 * 代码实现: 1. MyPool.java 连接池类, 2. 指定全局参数: 初始化数目、最大连接数、当前连接、 连接池集合 3. 构造函数:循环创建3个连接 4. 写一个创建连接的方法 5. 获取连接 ------> 判断: 池中有连接, 直接拿 ------> 池中没有连接, ------> 判断,是否达到最大连接数; 达到,抛出异常;没有达到最大连接数, 创建新的连接 6. 释放连接 -------> 连接放回集合中(..) * */ public class MyPool { private int init_count=3; ////初始化连接数目; private int max_count=6; //最大连接数目 private int current_count=0; //记录当前的连接数 //连接池,存放所有初始化连接 private LinkedList<Connection> pool=new LinkedList<Connection>(); //1、构造函数,初始化连接放入连接池中 public MyPool(){ //初始化 for (int i = 0; i < 3 ; i++) { //把连接加入连接池 current_count ++; final Connection connection=createConnection(); pool.addLast(connection); } } //2、创建一个新的连接方法 public Connection createConnection(){ try { Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); String url="jdbc:sqlserver://localhost:1433;DataBaseName=Test"; String user="sa"; String pass="123456"; final Connection connection= DriverManager.getConnection(url,user,pass); //对connection创建其代理对象 /**********************对对象代理***************/ Connection proxyConnection=(Connection)Proxy.newProxyInstance( connection.getClass().getClassLoader(), //类加载器 //connection.getClass().getInterfaces(), //目标对象实现的接口 new Class[]{Connection.class}, //目标对象实现的接口 new InvocationHandler() { //当调用对象方法的时候,会自动出发本代码。 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result=null; //当前执行的方法的方法名 String methodName=method.getName(); //判断当执行了close方法的时候,把链接放入连接池 if ("close".equals(methodName)) { System.out.println("begin:当前执行close方法"); current_count--; pool.add(connection); System.out.println("当前连接已放入连接池!"); }else { //调用目标对象方法 result=method.invoke(connection, args); } //调用目标对象方法 result=method.invoke(connection, args); return result; } }); return proxyConnection; } catch (Exception e) { // TODO Auto-generated catch block throw new RuntimeException(); } } //3、获取连接,外界没必要获取这个方法,内部判断生成 private Connection getConnection(){ //1、判断连接池中是否有链接,如果有连接,直接从连接池中获取 if (pool.size()>0) { return pool.removeFirst(); } //2、连接池中没有连接,判断,如果没有到达最大连接数目,创建 if (current_count<max_count) { //记录当前使用的连接数 current_count++; //创建连接 return createConnection(); } //3、如果当前已经到达最大的连接数目,抛出异常 throw new RuntimeException("当前链接数目已达到最大连接限度!"); } //4、释放连接 public void realeaseConnection(Connection connection){ //判断池的数目如果小于初始化数目 if (pool.size()<init_count) { current_count--; pool.add(connection); }else { //关闭 try { connection.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public static void main(String[] args) throws SQLException { // TODO Auto-generated method stub MyPool pool=new MyPool(); System.out.println("当前连接数目:"+pool.current_count); //使用连接 pool.getConnection(); pool.getConnection(); Connection con1=pool.getConnection(); Connection connection=pool.getConnection(); pool.realeaseConnection(connection); /* * 希望:当关闭连接的时候,要把连接放入连接池!【当调用Connection接口的close方法时候,希望触发pool.addLast(con);操作】 * 把连接放入连接池 * 解决1:实现Connection接口,重写close方法,单Connection接口的方法是在太多了。 * 解决2:动态代理 * (1)、Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。 * (2)该类下有newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 方法 * 返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。 * ClassLoad:当前使用的类加载器 * Class<?> interface 目标对象(Connection)实现的接口类型 * invocationHandler h 事务处理器,当执行上面接口中的方法的时候,就会自动触发 * 事件处理器的代码,把当前执行方法(method)作为参数传入。 * InvocationHandler invoke(Object proxy, Method method, Object[] args) 在代理实例上处理方法调用并返回结果。 * */ con1.close(); System.out.println("连接池:"+pool.pool.size()); System.err.println("当前连接数目:"+pool.current_count); } }
运行结果(其中讲到了一个重要的概念:事务代理,当我们想要给close()方法添加一个必要的方法,当执行close方法的时候,我们想将其加入到连接池中,相当于把close当做一个触发器,一旦执行,就会自动的触发将其加入缓冲池中)