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

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

 

前言

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

分析

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

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

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

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

 

String testQuery = getTestQuery(); if (testQuery != null) { Configuration.logDebug ( this + ": testing connection with query [" + testQuery + "]" ); Statement stmt = null; try { stmt = connection.createStatement(); ResultSet rs = stmt.executeQuery(testQuery); rs.close(); stmt.close(); } catch ( SQLException e) { throw new CreateConnectionException ( "Error executing testQuery" , e ); } Configuration.logDebug ( this + ": connection tested OK" ); } else { Configuration.logDebug ( this + ": no test query, skipping test" ); }

如果失败,抛出CreateConnectionException异常。

注意ConnectionPoolborrowConnection方法,其中有一段:

 

Iterator it = connections.iterator(); while ( it.hasNext() && ret == null ) { xpc = (XPooledConnection) it.next(); if (xpc.isAvailable()) { try { ret = xpc.createConnectionProxy ( hmsg ); Configuration.logDebug( this + ": got connection from pool, new size: " + availableSize() + "/" + totalSize()); } catch ( CreateConnectionException ex ) { String msg = this + ": error creating proxy of connection " + xpc; Configuration.logWarning( msg , ex); it.remove(); xpc.destroy(); } } }   

可以看到,其做的事情,就是遍历连接池中的连接,一个一个的测试。注意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。

 

   

你可能感兴趣的:(java)