JDBC连接池设计--Mysql

来源:互联网 发布:淘宝店id限购 编辑:程序博客网 时间:2024/05/21 09:28

JDBC连接数据库,并非是一件轻松的差事。数据库连接不仅仅在应用服务器和数据库服务器之间建立Socket Connection,还需要交换若干次数据用来验证等,以及系统资源和进程,日志的处理,所以数据库连接池在设计应用中是不可忽视的!缓解系统很大的压力!

思考:在创建好Connection之后,我们会习惯性地在用完后connection后,调用它的close()方法,有什么好的设计方法使其在调用close()方法和数据库连接池挂钩,即判断当前连接是否达到最大值?如果是,直接关闭,反之-将其加入数据库连接池中,待后续再用!

1.数据库连接池类DBConnection

public class DBPool {//容器--装Connectionprivate static Vector<Connection> vector;//设置的 连接池----最大连接数private final int POOL_MAX_Size = 20;//获取一个Connection实例public synchronized Connection getConnection() throws Exception{Connection con;if(vector == null){vector = new Vector<Connection>();}if(vector.isEmpty()){con = createConnection();}else{int index = vector.size()-1;//从连接池-- 获取一个Connectioncon = vector.get(index);//连接池--移除 被使用的Connectionvector.remove(index);}return con;}//处理一个Connection用完后的逻辑public synchronized void releaseConnection(Connection con) throws Exception{//连接池容器--是否满了if(vector.size() == POOL_MAX_Size){try {//直接关闭连接con.close();} catch (SQLException e) {throw new Exception("When closing a Connection throws exception");}}else{//没有满,将该Connection放入连接池,后续再用vector.add(con);}}//创建一个Connection连接private static Connection createConnection() throws Exception{Connection con;try{Class.forName("com.mysql.jdbc.Driver");con = DriverManager.getConnection("jdbc:mysql://192.168.125.107:3306/naladb?autoReconnect=true&useUnicode=true&characterEncoding=UTF8","naladb","nalanala");} catch(ClassNotFoundException ex){throw new Exception("ClassNotFoundException when loading jdbc driver");} catch(SQLException ex){throw new Exception("SQLException  when loading jdbc driver");}return con;}}

=====在此,数据库连接池基本写好了(当然是简单的,没有考虑连接时间处理等,但是这是核心思想),那么在用完Connection后,我们可以选择调用DBPolol的releaseConnection(Connection con)来处理,但是 上面"思考",提到我们习惯性是调用Connection的close()方法,这样看上去很简洁规范(PreparedStatement,ResultSet也是调用close()来关闭连接)

肿麽办?就应该想到一些设计模式,有装饰,动态代理等,在这采用动态代理来完美处理这一问题!

动态代理----->三个前提:

1.接口:Connection  就是一个接口啊,有了。

2.接口的实现类:也有啊,上面的createConnection()不就得到一个实现了connection接口的类的实例么!ok

3.InvocationHandler接口的实现类:自己新创建一个类来实现该接口不就好了?也行


public class ConnectionHandler implements InvocationHandler {//Connection的实例private Connection con;//数据库连接池----(一般一个数据库使用一个连接池)private DBPool dbpool;public ConnectionHandler(DBPool dbPool){this.dbpool = dbPool;}//绑定当前的Connection实例public  Connection bind(Connection con){this.con = con;//创建Connection的代理对象Connection proxyCon =  (Connection) Proxy.newProxyInstance(con.getClass().getClassLoader(), con.getClass().getInterfaces(), this);return proxyCon;}/** * 动态代理的类---class sun.proxy.$Proxy0  实现了:Connection接口,也继承了实现该接口的类,所以它有真实对象con 所有的方法! */@Overridepublic Object invoke(Object object, Method method, Object[] args)throws Throwable {Object obj = null;//如果 执行的是:close()方法if("close".equals(method.getName())){//调用数据库连接池的releaseConnection(Connection con)方法this.dbpool.releaseConnection(con);}else{//否则,调用自己的方法----这里反射机制,调用真实的Connection的实例con,而不是Proxy0代理对象obj = method.invoke(con, args);}return obj;}}

当然也要修改连接池DBPool中的getConnection()方法里面内容-----》仅仅修改了这两句话

     //创建Connection的代理机制
     ConnectionHandler connectionHandler = new ConnectionHandler(this);
   //返回con代理对象
     return connectionHandler.bind(con);


public synchronized Connection getConnection() throws Exception{Connection con;if(vector == null){vector = new Vector<Connection>();}if(vector.isEmpty()){con = createConnection();}else{int index = vector.size()-1;//从连接池-- 获取一个Connectioncon = vector.get(index);//连接池--移除 被使用的Connectionvector.remove(index);}//创建Connection的代理机制ConnectionHandler connectionHandler = new ConnectionHandler(this);//返回con代理对象return connectionHandler.bind(con);}

测试类:------

public class JDBCPoolJunit {public static void main(String[] args) throws Exception {DBPool dbPool = new DBPool();Connection conProxy = dbPool.getConnection();System.out.println("================================");System.out.println(conProxy);System.out.println(conProxy.getClass());System.out.println("===============================");conProxy.close();long timeStart = new Date().getTime();PreparedStatement statement = conProxy.prepareStatement("select t.id from trade t,user u where t.buyer_id=u.id and t.date_created>'2013-01-01 00:00:00' and u.username like '%qq%'");ResultSet re = statement.executeQuery();long timeEnd = new Date().getTime();System.out.println((timeEnd-timeStart)/1000.0+"秒");}}

结果:

================================
com.mysql.jdbc.Connection@a3d4cf ---->代理对象  如果我们打印System(con)结果也是:com.mysql.jdbc.Connection@a3d4cf,但

是它的类:class com.mysql.jdbc.Connection


class sun.proxy.$Proxy0------>代理类
===============================
2.991秒

根据结果知道:调用close()方法后,该连接并没有关闭,还可以进行sql语句查询,这就是动态代理的好处!  我们要 认识  代理类被代理类关系区别



原创粉丝点击