I am working on a spring-boot application where I need XA to ensure that JPA updates and JMS messages generation is either all or nothing. The problem is when a rollback happens, DB is rolling back, but not the JMS message.
I am running with embedded tomcat and JMS server is Weblogic12c.
I followed the JTA directions from the spring-boot documentation and added the dependencies for Atomikos (transactions-jms
, transactions-jta
, transactions-jdbc
) as well as spring-boot-starter-jta-atomikos
.
In the logs I can see that Atomikos is running and what appears to be the JPA queries being added to the XA transaction, but nothing for JMS.
The logs below come from code where I do JPA updates, then send JMS message using JMSTemplate
, then I throw a RuntimeException
:
INFO c.a.jdbc.AbstractDataSourceBean - AtomikosDataSoureBean 'dataSource': getConnection ( null )...
INFO c.a.jdbc.AbstractDataSourceBean - AtomikosDataSoureBean 'dataSource': init...
INFO c.a.i.imp.CompositeTransactionImp - addParticipant ( XAResourceTransaction: 31302E33302E36302E3137332E746D30303030313030303434:31302E33302E36302E3137332E746D31 ) for transaction 10.30.60.173.tm0000100044
INFO c.a.d.xa.XAResourceTransaction - XAResource.start ( 31302E33302E36302E3137332E746D30303030313030303434:31302E33302E36302E3137332E746D31 , XAResource.TMJOIN ) on resource dataSource represented by XAResource instance oracle.jdbc.driver.T4CXAResource@621c7c98
INFO c.a.i.imp.CompositeTransactionImp - registerSynchronization ( com.atomikos.jdbc.AtomikosConnectionProxy$JdbcRequeueSynchronization@f4a9582b ) for transaction 10.30.60.173.tm0000100044
INFO c.a.jdbc.AtomikosConnectionProxy - atomikos connection proxy for oracle.jdbc.driver.LogicalConnection@650a9087: calling prepareStatement(select prjct_rvsn_seq_num_seq.nextval from dual)...
INFO c.a.jdbc.AtomikosConnectionProxy - atomikos connection proxy for oracle.jdbc.driver.LogicalConnection@650a9087: isClosed()...
INFO c.a.jdbc.AtomikosConnectionProxy - atomikos connection proxy for oracle.jdbc.driver.LogicalConnection@650a9087: calling getWarnings...
INFO c.a.jdbc.AtomikosConnectionProxy - atomikos connection proxy for oracle.jdbc.driver.LogicalConnection@650a9087: calling clearWarnings...
INFO c.a.jdbc.AtomikosConnectionProxy - atomikos connection proxy for oracle.jdbc.driver.LogicalConnection@650a9087: close()...
INFO c.a.d.xa.XAResourceTransaction - XAResource.end ( 31302E33302E36302E3137332E746D30303030313030303434:31302E33302E36302E3137332E746D31 , XAResource.TMSUCCESS ) on resource dataSource represented by XAResource instance oracle.jdbc.driver.T4CXAResource@621c7c98
INFO c.c.ola.order.service.OrderService - Order saved of scope:FIRST with app ID:1127662
INFO c.c.o.o.s.OrderEventBroadcaster - Sending message on queue jms/AppQueue
DEBUG o.s.jms.core.JmsTemplate - Executing callback on JMS Session: weblogic.jms.client.WLSessionImpl@24cfb8e8
DEBUG o.s.j.s.d.JndiDestinationResolver - Located object with JNDI name [jms/AppQueue]
DEBUG o.s.jms.core.JmsTemplate - Sending created message: TextMessage[null, <?xml version="1.0" encoding="...]
INFO c.a.d.xa.XAResourceTransaction - XAResource.rollback ( 31302E33302E36302E3137332E746D30303030313030303434:31302E33302E36302E3137332E746D31 ) on resource dataSource represented by XAResource instance oracle.jdbc.driver.T4CXAResource@621c7c98
INFO com.atomikos.icatch.jta.Sync2Sync - afterCompletion ( STATUS_ROLLEDBACK ) called on Synchronization: org.hibernate.resource.transaction.backend.jta.internal.synchronization.RegisteredSynchronization@25385341
INFO c.a.i.imp.CompositeTransactionImp - rollback() done of transaction 10.30.60.173.tm0000100044
In my googling, I haven't seen much. It appears that it should just work, but it isn't where did I drop the ball?
UPDATE:
Below is how I'm creating my ConnectionFactory
:
@Bean
FactoryBean<ConnectionFactory> jmsConnectionFactory(final JndiTemplate jndiTemplate) {
final JndiObjectFactoryBean beanFactory = new JndiObjectFactoryBean();
beanFactory.setJndiTemplate(jndiTemplate);
beanFactory.setJndiName("jms.remoteConnectionFactory");
beanFactory.setProxyInterface(ConnectionFactory.class);
return (FactoryBean) beanFactory;
}
UPDATE:
Since the logs referenced weblogic.jms.client.WLSessionImpl
instead of something with "XA" in the name, I investigated what weblogic was returning. The instance returned from "jms.remoteConnectionFactory" was weblogic.jms.client.JMSXAConnectionFactory
which does not implement javax.jms.XAConnectionFactory
which seems weird. I don't know why that is or if that is problem, but it seems like it could be.
My solution was to set sessionTransacted
to true
on the jmsTemplate
.
@Bean
JmsTemplate cciSitesJmsTemplate(@CciSites final ConnectionFactory connectionFactory, final JndiDestinationResolver destinationResolver) {
final JmsTemplate jmsTemplate = new JmsTemplate(connectionFactory);
jmsTemplate.setDestinationResolver(destinationResolver);
// NOTE: sessionTransacted is required to join the XA transaction
jmsTemplate.setSessionTransacted(true);
return jmsTemplate;
}