xa transactions over camel routes
TRANSCRIPT
XA Transactions over Camel Routes
Managing multiple transactional resources
Multiple transactional resources
from('jms:inbound?transacted=true').log('Processing message ${body}').policy('DB_PROPAGATION_REQUIRED'). to('sql:insert into audit_log (message) values (:#${body})').end().policy('JMS_PROPAGATION_REQUIRED'). to('jms:outbound').end()
Multiple transactional resources
@Bean DataSource dataSource() { new JdbcDataSource( url: 'jdbc:h2:tcp://localhost/~/test', user: '', password: '' ) }
@Bean ConnectionFactory connectionFactory() { new ActiveMQConnectionFactory( brokerURL: 'tcp://localhost:61616' ) }
Multiple transactional resources
@Bean PlatformTransactionManager dbTransactionManager() { new DataSourceTransactionManager(dataSource: dataSource()) }
@Bean PlatformTransactionManager jmsTransactionManager() { new JmsTransactionManager(connectionFactory: connectionFactory()) }
Multiple transactional resources
@Bean(name = 'DB_PROPAGATION_REQUIRED') SpringTransactionPolicy dbPropagationRequired() { new SpringTransactionPolicy( transactionManager: dbTransactionManager(), propagationBehaviorName: 'PROPAGATION_REQUIRED' ) }
@Bean(name = 'JMS_PROPAGATION_REQUIRED') SpringTransactionPolicy jmsPropagationRequired() { new SpringTransactionPolicy( transactionManager: jmsTransactionManager(), propagationBehaviorName: 'PROPAGATION_REQUIRED' ) }
One single transaction policy
from('jms:inbound?transacted=true').log('Processing message ${body}').transacted('PROPAGATION_REQUIRED').to('sql:insert into audit_log (message) values (:#${body})').to('jms:outbound')
XA transactions & 2PC
* Extracted from DZone’s article “XA Transactions (2PC): A Simple Guide” (see references)
Atomikos transaction manager
* Extracted from “Apache Camel’s Developer Cookbook” (see References)
XA-capable resources
@Bean XADataSource dataSource() { new JdbcDataSource( url: 'jdbc:h2:tcp://localhost/~/test', user: '', password: '' ) }
@Bean XAConnectionFactory connectionFactory() { new ActiveMQXAConnectionFactory( brokerURL: 'tcp://localhost:61616' ) }
Atomikos wrappers@BeanAtomikosDataSourceBean atomikosDataSource() { new AtomikosDataSourceBean( uniqueResourceName: 'xa.h2.oracle', xaDataSource: dataSource() )}
@Bean(destroyMethod = 'close')AtomikosConnectionFactoryBean atomikosConnectionFactory() { def factory = new AtomikosConnectionFactoryBean( uniqueResourceName: 'xa.amq', xaConnectionFactory: connectionFactory(), maxPoolSize: 10, ignoreSessionTransactedFlag: false ) factory.init() factory}
Atomikos wrappers
@BeanUserTransactionImp atomikosUserTransaction() { new UserTransactionImp(transactionTimeout: 300)}
@Bean(initMethod = 'init', destroyMethod = 'close')TransactionManager atomikosTransactionManager() { new UserTransactionManager()}
Single transaction manager & policy
@BeanPlatformTransactionManager xaTransactionManager() { new JtaTransactionManager( transactionManager: atomikosTransactionManager(), userTransaction: atomikosUserTransaction() )}
@Bean(name = 'PROPAGATION_REQUIRED')SpringTransactionPolicy propagationRequired() { new SpringTransactionPolicy( transactionManager: xaTransactionManager(), propagationBehaviorName: 'PROPAGATION_REQUIRED' )}
Error handler route
onException(Throwable).useOriginalMessage().maximumRedeliveries(5).redeliverDelay('5000').to('jms:dlq').log(ERROR, 'Error: \${exception.stacktrace}').end()
Final thoughts
XA is:
- More complex- More expensive- Hard to test- Slower
Use or not?
- Transaction required?- Multiple database updates?- Multiple JMS destinations?- Compensation?
References
- XA transactions & 2PChttp://www.javaworld.com/article/2077714/java-web-development/xa-transactions-using-spring.htmlhttps://dzone.com/articles/xa-transactions-2-phase-commit
- Atomikoshttps://www.atomikos.com/Documentation/GettingStarted
- Camel transaction policieshttp://camel.apache.org/transactional-client.html
- Camel error handlinghttp://camel.apache.org/error-handler.html
- Apache Camel’s Developer Cookbook:https://www.packtpub.com/application-development/apache-camel-developers-cookbook