分析Atomikos数据连接池源码,弄清testQuery

分析Atomikos数据连接池源码,弄清testQuery

分类: java2010-03-18 17:19 1163人阅读 评论(0) 收藏 举报

作者:fbysss
msn:[email protected] 
blog:blog.csdn.net/fbysss
声明:本文由fbysss原创,转载请注明出处
关键字:Atomikos数据连接池

前言

     Atomikos数据连接池,国内有一些应用,但testQuery这个属性,在网上均是简单配置,并没有做特殊说明。通过对Atomikos源码的分析,发现这里很有学问。

分析

    我们使用的数据源是AtomikosDataSourceBean,在其doInit方法中, 会调用AtomikosXAConnectionFactory的createPooledConnection方法,该方法会返回一个AtomikosXAPooledConnection连接。

而AtomikosXAPooledConnection是AbstractXPooledConnection的一个子类,AbstractXPooledConnection中,在调用createConnectionProxy时,会调用testUnderlyingConnection方法,用于进行测试。

在AtomikosDataSourceBean的getConnection时,调用connectionPool的borrowConnection方法从而调用AbstractXPooledConnection中的createConnectionProxy,从而调用testUnderlyingConnection方法。

可以看testUnderlyingConnection中的关键代码,一旦设置了testQuery,每次getConnection的时候,就会连接查询一次(通过jprofiler也可以检测出来):

[java] view plaincopy

  1. String testQuery = getTestQuery();  
  2.     if (testQuery != null) {  
  3.         Configuration.logDebug ( this + ": testing connection with query [" + testQuery + "]" );  
  4.         Statement stmt = null;  
  5.         try {  
  6.             stmt = connection.createStatement();  
  7.             ResultSet rs = stmt.executeQuery(testQuery);  
  8.             rs.close();  
  9.             stmt.close();  
  10.         } catch ( SQLException e) {  
  11.             throw new CreateConnectionException ( "Error executing testQuery" ,  e );  
  12.         }  
  13.         Configuration.logDebug ( this + ": connection tested OK" );  
  14.     }  
  15.     else {  
  16.         Configuration.logDebug ( this + ": no test query, skipping test" );  
  17.     }  

如果失败,抛出CreateConnectionException异常。

注意ConnectionPool的borrowConnection方法,其中有一段:

[java] view plaincopy

  1. Iterator it = connections.iterator();  
  2.   
  3. while ( it.hasNext() && ret == null ) {  
  4.   
  5.    xpc = (XPooledConnection) it.next();  
  6.   
  7.   
  8.   
  9.    if (xpc.isAvailable()) {  
  10.   
  11.        try {  
  12.   
  13.           ret = xpc.createConnectionProxy ( hmsg );  
  14.   
  15.           Configuration.logDebug( this + ": got connection from pool, new size: " + availableSize() + "/" + totalSize());  
  16.   
  17.        } catch ( CreateConnectionException ex ) {  
  18.   
  19.           String msg = this +  ": error creating proxy of connection " + xpc;  
  20.   
  21.           Configuration.logWarning( msg , ex);  
  22.   
  23.           it.remove();  
  24.   
  25.           xpc.destroy();  
  26.   
  27.        }  
  28.   
  29.    }  
  30.   
  31. }  

  

可以看到,其做的事情,就是遍历连接池中的连接,一个一个的测试。注意ret = xpc.createConnectionProxy ( hmsg ),一旦该方法抛出CreateConnectionException,就执行it.remove();即将该连接从连接池中删除。

如果设置了testQuery属性,每次获取连接时testQuery,能够保证应用服务器启动之后,与数据库连接暂时中断之后,能够在下一次请求时,自动重新建立连接。

连接池是如何自动建立连接的呢?其实就是简单的把无效的连接一个一个删掉,直到全部删光了,池里面没有有效(poolAvailableSize==0,是根据连接的isTerminated状态来判断的,而不是是否被重置过)的连接了,这样根据连接池的机制,就会调用growPool方法去请求新的连接。

但是这样有性能消耗,而且还不小。对于网站展示部分,不需要实时去检测,可以考虑采用定时检测的方法:

n  首先,保证testQuery为空,不配置。

n  创建一个DbPoolMonitorService类,实现ApplicationContextAware接口,这样应用启动时,会自动注入ApplicationContext对象。这样,可以在service中,调用getBean方法,获取AtomikosDataSourceBean的实例,

AtomikosDataSourceBean ads = (AtomikosDataSourceBean)ctx.getBean(“jtaDataSource”);

然后,ads中能够获得minPoolSize/maxPoolSize/availablePoolSize/totalPoolSize等属性,可以做一个界面来监测数据连接池的使用和配置情况,甚至可以动态修改这些属性。

n  做一个定时器,调用一个DbPoolMonitorService定期去手工test。使用SELECT 1 语句即可。

n  注意:try 部分ads.setTestQuery (“SELECT 1”);然后调用BaseDao的实例去执行一句话,依然可以使”SELECT 1” 。finally部分ads.setTestQuery(null),以保证不对其他部分造成后续影响。

n  可根据用户访问量,来决定定时周期,一般10分钟左右即可。这样,避免了每次获取连接去做一次检测操作,又能够将故障限制在一定时间范围内。是一个较好的折衷做法。

补充:我们再看 ret = xpc.createConnectionProxy ( hmsg )这句话,如果这时候DB和WebAppServer的网络链路已经正常,DB正常运行,返回将不是空,会退出循环。这样,如果连接池中的连接是多个,则只会生成1个新的连接,如果要保证连接池机制的效果,需要在写监控程序的时候,去取得所有有效连接,循环test。

猜你喜欢

转载自blog.csdn.net/zzy7075/article/details/107153329