Sunday 20 May 2012

Atomikos and Oracle AQ: connections pool problem



Don't use Atomikos jms ConnectionFactoryBean pooling with Oracle AQ as they recommend in documentation! You will not use the pool indeed. How to use it right?

In example from Atomikos documentation we are creating oracleDataSource and AQJmsFactory uses it to create XA factory.
And Atomikos JMS factory bean works like an adapter/decorator for this XA factory to make it transaction-aware and to create connection pool:


oracle.jdbc.xa.client.OracleXADataSource  xaDataSource = new oracle.jdbc.xa.client.OracleXADataSource();
XAQueueConnectionFactory xaQueueConnectionFactory = AQjmsFactory.getXAQueueConnectionFactory ( xads );
AtomikosConnectionFactoryBean pooledQueueConnectionFactoryBean = new AtomikosConnectionFactoryBean();
pooledQueueConnectionFactoryBean.setXaConnectionFactory ( xaQueueConnectionFactory ); 
//...set pool settings in pooledQueueConnectionFactoryBean ...


But behind the scene if you will profile application which uses this code, you will find that Atomikos have no access to JMS connection to use it in pool(naturally, as Oracle AQ uses jdbc connection instead) and each closeSession delegates to Oracle AQ conn factory which calls PhysicalConnection.close() on jdbc connection. And pool is not working as expected. If your app has few listeners and each of them calls receive frequently you will create/close jdbc connections each time and performance would be horrible.

The problem also is that you can't enable connection caching in OracleXADataSource and use it's pool(if you will do this AQjmsFactory will throw exception), and dbcp and c3p0 pools are not working either as AQ doesn't work with proxy this implementations create around instance of oracle connection.

The only solution which works for us is to use atomikos xaDataSourceBean and than non-xa jms queue connection factory:

oracle.jdbc.xa.client.OracleXADataSource xaDataSource = new oracle.jdbc.xa.client.OracleXADataSource();
AtomikosDataSourceBean pooledDataSourceBean = new AtomikosDataSourceBean();
pooledDataSourceBean.setXaDataSource(xaDataSource);
//...set pool settings in pooledDataSourceBean ...
QueueConnectionFactory queueConnectionFactory = AQjmsFactory.getQueueConnectionFactory ( pooledDataSourceBean );


This will allow you to use XA-aware data source and atomikos connection pool now will work, as it is between AQ JMS connection factory and db data source.