[转]JDBC与连接池

 

原文地址: http://blog.csdn.net/popkiler/archive/2007/09/07/1775629.aspx

 

 

JDBC运作方式
    对于JDBC Driver来说,连接数据库却并非一件轻松差事。数据库连接不仅仅是在应用服务器与数据库服务器之间建立一个Socket Connection,连
接建立之后,应用服务器和数据库服务器之间还需要交换若干次数据(验证用户密码、权限等),然后,数据库开始化连接会话句柄,记录联机日志,
为此连接分配相应的处理进程和系统资源

    数据库连接池的基本原理是在内部对象池中维护一定数量的数据库连接,并对外暴露数据库连接获取和返回方法。外部使用都可通过getConnection方
法获取连接,使用完毕后再通过releaseConnection方法将连接返回,注意此时连接并没有关闭,而是由连接池管理器回收,并为下一次使用做好准备。
    一个最小化的数据库连接池实现:

  /**
   *获取数据库连接,如果当前池中有可用连接,则将池中最后一个返回,如果没有,则新建一个返回
   
*/

  
public  synchronized Connection getConnection()throws DBException {
   
if(pool==null){
    pool
=new Vector();
   }

   Connection conn;
   
if(pool.isEmpty()){
    conn
=createConnection();
   }
else{
    
int last_idx=pool.size()-1;
    conn
=(Connection)pool.get(last_idx);
    pool.remove(pool.
get(last_idx));
   }

   
return conn;
  }

  
/**
   *将使用完毕的数据库连接池放回备用池
   *判断当前池中连接数是否已经超过阈值(POOL_MAX_SIZE)如果超,则关闭该连接,否则施加池中以备下次重用
   
*/

  
public  synchronized  void  releaseConnection(Connection conn) {
   
if(pool.size()>POOL_MAX_SIZE){
    
try{
     conn.close();
    }
catch(SQLException e){
     e.printStackTrace();
    }

   }
else{
    pool.add(conn);
   }

  }

  
/**
   * 读取数据库配置信息,并从数据库连接池中获得数据库连接
   * @return
   * @throws DBException
   
*/

  priavte 
static  Connection createConnection()throws DBException {
   Connection conn;
   
try{
    Class.forName(
"oracle.jdbc.driver.OracleDriver");
    conn
=DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:oracle","personal","personal");
    
return conn;
   }
catch(ClassNotFoundException e){
    
throw new DBException("ClassNotFounDException when loading JDBC Driver");
   }
catch(SQLException e){
    
throw new DBException("SQLException when loading JDBC Driver");
   }

  }

}

先脱离连接池本身的具体实现,我们看看这段代码在实际应用中可能产生的问题,注意到,由于getConnection方法返回的是一个标准的JDBC
Connection,程序员由于编程习惯,可能会习惯性的调用其close方法关闭连接。如此一来,连接无法得到重用,数据库连接池机制开同虚设。为了
解决这个问题,比较好的途径有:
 1。 Decorator模式
 2。 Dynamic Proxy模式

Decorator模式
 “Decorator模式的主要目的是利用一个对象,透明地为另一个对象添加新的功能”,简单来说,就是通过一个Decorator对原有对象进行封装
,同时实现与原有对象相同的接口,从而得到一个基于原有对象的,对既有接口的增强性实现。
 对于前面讨论的Connection释放的问题,理所当然,我们首先想到的是,如果能让JDBC Connection在执行close操作时自动将自己返回到
数据库连接池中。但是,JDBC Connection自己显然无法根据实际情况判断何去何从。此时,引入Decorator模式来解决我们所面对的问题:

public   class  ConnectionDecorator  implements  Connection {
  Connection dbConn;
  
public ConnectionDecorator(Connection conn){
   
this.dbConn=conn;
  }

  
public void close()throws SQLException{
   
this.dbConn.close();
  }

  
public void commit()throws SQLException{
   
this.dbConn.commit();//调用实际连接的commit方法
  }

 }

 目标很清楚,通过这样的封装,我们的ConnectionDecorator对于外部的程序员而言,调用方法与普通的JDBC Connection完全相同,而在
内部通过对ConnectionDecorator的修改,我们就可以透明地改变现有实现,为之增加新特性:

public   class  PooledConnection  extends  ConnectionDecorator  implements  Connection {
  
private ConnectionPool connPool;
  
public PooledConnection(ConnectionPool pool,Connection conn){
   
super(conn);
   connPool
=pool;
  }

  
public void close()throws SQLException{
   connPool.releaseConnection(
this.dbconn);
  }

 }

 为了应用新的PooledConnection,我们需要对原本的DBConnectionPool.getConnection和releaseConnection方法稍做改造:

public   synchronized  Connection getConnection() throws  DBException {
  
if(pool==null){
   poo
=new Vector();
  }

  Connection conn;
  
if(pool.isEmpty()){
   conn
=createConnection();
  }
else{
   
int last_idx=pool.size()-1;
   conn
=(Connection)pool.get(last_idx);
   pool.remove(pool.get(last_idx);
  }

  
return new PooledConnection(this,conn);//就这不同啦
 }

 
public   synchronized   void  releaseConnection(Connection conn) {
  
if(conn instanceof PooledConnection||pool.size()>POOL_MAX_SIZE){
   
try{
    conn.close();
   }
catch(SQLException e){
    e.printStackTrace();
   }

  }
else{
   pool.add(conn);
  }

 }

Dynamic Proxy模式
 我们的目标是引入数据库连接池机制的同时,保持JDBC Connection对外接口不变。前面通过Decorator模式实现了这一目标,但由于
Decorator模式要求实现与目标对象一致的接口,Connection接口中定义的方法众多,我们也只能照单全收。
 Dynamic Proxy模式则良好地解决了这一问题。通过实现一个绑定到Connection对象的InvocationHandler接口实现,我们可以在
Connection.close方法被调用时将其截获,并以我们自己实现的close方法将其替代,使连接返回到数据库连接池等待下次重用,而不是直接关
闭。
 下面是ConnectionHandler类,它实现了InvocationHandler接口,按照Dynamic Proxy机制的定义,invoke方法将截获所有代理对象的
方法调用操作,这里我们通过invoke方法截获close并进行处理:

public   class  ConnectionHandler  implements  InvocationHandler {
  Connection dbconn;
  ConnectionPool pool;

  
public ConnectionHandler(ConnectionPool connPool){
   
this.pool=connPool;
  }

  
//将动态代理绑定到指定Connection
  public Connection bind(Connection conn){
   
this.dbconn=conn;

   
//绑定到Connection对象的InvocationHandler接口实现(我的理解,可能有误)
   Connection proxyConn=(Connection)Proxy.newProxyInstance(conn.getClass().getClassLoader(),
                                                        conn.getClass().getInterfaces(),
this);
   
return proxyConn;
  }

  
/**
   *方法调用拦截器
   *判断当前调用的方法是否“close”方法,如是,调用pool.releaseConnection方法作为标准close方法的替代
   
*/

  
public Object invoke(Object proxy,Method method,Object[] args)throws Throwable{
   Object obj
=null;
   
//如果调用的是close方法,则用pool.releaseConnection方法将其替换
   if("close".equals(method.getName))){
    pool.releaseConnection(dbconn);
   }
else{
    obj
=method.invoke(dbconn,args);
   }

   
return obj;
  }

 }


 配合Dynamic Proxy模式,我们的DBConnectionPool.getConnection方法也做了一点小小的修改:

 

public   synchronized  Connection getConnection() throws  DBException {
  
if(pool==null){
   pool
=new Vector();
  }

  Connection conn;
  
if(pool.isEmpty()){
   conn
=createConnection();
  }
else{
   
int last_idx=pool.size()-1;
   conn
=(Connection)pool.get(last_idx);
   pool.remove(pool.get(last_idx);
  }

  ConnectionHandler connHandler
=new ConnectionHandler(this);
  
return connHandler.bind(conn);
 }
 

摘自:《深入浅出Hibernate》

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值