作者:fbysss
msn:jameslastchina@hotmail.com
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也可以检测出来):
- 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异常。
注意ConnectionPool的borrowConnection方法,其中有一段:
- 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。
- 上一篇:openfire安装备忘
- 下一篇:SVN分支与合并透析