JDBC连接池设计--Mysql

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

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

1.数据库连接池类DBConnection

public class DBPool {
	//容器--装Connection
	private 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;
			//从连接池-- 获取一个Connection
			con = vector.get(index);
			//连接池--移除 被使用的Connection
			vector.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 所有的方法!
	 */
	@Override
	public 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;
			//从连接池-- 获取一个Connection
			con = vector.get(index);
			//连接池--移除 被使用的Connection
			vector.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语句查询,这就是动态代理的好处!  我们要 认识  代理类被代理类关系区别



  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值