I am trying to get XA transactions working in a Spring v3 application inside WebSphere v7.
My App Context reads:
<bean id="jmsConnectionFactory"
class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="jms/MQConnectionFactory"/>
<property name="resourceRef" value="true"/>
</bean>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="jmsConnectionFactory"/>
</bean>
<jee:jndi-lookup id="myDB" jndi-name="jdbc/myDB"/>
<bean id="txManager"
class="org.springframework.transaction.jta.WebSphereUowTransactionManager" />
<tx:annotation-driven transaction-manager="txManager"/>
I'm referencing this article that says mix in the UOW txn manager and you'll be fine. But it doesn't work that way. Instead, in the following code, the message is destructively read and is not rolled back when an exception is thrown.
The transactional logic is (in scala):
#Transactional(rollbackFor = Array(classOf[Throwable]))
def processNextMessage(category: String) = {
val maybeMessage = readNextMessage(category) // <- this is a destructive read
for (message <- maybeMessage) {
// this is temporary code for testing
throw new RuntimeException("blaaaaaah")
// end temporary code
// sendToQueue(message, queue)
// writeToMessageStore(message)
}
}
Can anyone advise how I can use WebSphere's JTA transaction manager with Spring?
First of all, I would really like to see the code for readNextMessage as that may be the culprit.
Is the queue connection factory set up as an XA resource. You are trying to use JTA for transactions, so as far as I know you need to configure the message qcf accordingly.
You do not have to setup the JmsTemplate for transactions, as these are handled by the QueueConnectionFactory.
On a side note: if you are just dealing with mq, you can skip the UOW JTA provider and use transacted JMS sessions, which should work fine.
Related
We have implemented a spring message listener service and the main operation exposed by this service is multiple event driven database update.
The context looks like as below.
<bean id="consumerContainer"
class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="concurrentConsumers" value="${jms.consumerContainer.concurrentconsumers}"/>
<property name="maxConcurrentConsumers" value="${jms.consumerContainer.maxconcurrentconsumers}"/>
<property name="errorHandler" ref="errorHandler" />
<property name="connectionFactory" ref="jmsQueueConnectionFactory" />
<property name="destination" ref="listenerQueue" />
<property name="messageListener" ref="consumerContainer" />
<property name="receiveTimeout" value="10000" />
<property name="sessionTransacted" value="true" />
<property name="transactionManager" ref="txManager" />
</bean>
TX manager is hibernate.
<tx:annotation-driven transaction-manager="txManager" />
<bean id="txManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager" p:sessionFactory-ref="sessionFactory"/>
and annotated the concrete class with #Transactional.
We use Jboss application server support to integrate with MQ via jndi.
The problem here is if there are any exception at any layer in the listener, the overall transaction is not getting rolled back and the message does not move to back out queue. It's obvious that as we use Hibernate transaction manager, it's not aware of other resource like JMS transactions.
Can I replace this safely with JTA transaction as Jboss will handle overall transaction management? Is there any foreseen risk in doing so?
I believe its no longer needed to annotate the class with #Transactional if we are using JTA as below.
<bean id="jtatxManager" class="org.springframework.transaction.jta.JtaTransactionManager"/>
Thanks in advance.
Can I replace this safely with JTA transaction as Jboss will handle overall transaction management?
Yes, you can. You should just change your bean txManager definition.
I believe its no longer needed to annotate the class with #Transactional.
This is not true. You still need #Transactional. It allows spring to identify a transaction boundary.
I'm using Spring's DataSourceTransactionManager for transaction managment and JmsTemplate for sending messages to ActiveMQ queue. My problem is force to work in single transaction next algorithm:
Step 1: update DB;
Step 2: send message to queue;
Step 3: update DB;
Step 4: send message to queue.
As I understand from documentation for JmsTemplate, in my case I must set parameter "sessionTransacted" = true:
Setting this flag to "true" will use a short local JMS transaction when running outside of a managed transaction, and a synchronized local JMS transaction in case of a managed transaction (other than an XA transaction) being present. The latter has the effect of a local JMS transaction being managed alongside the main transaction (which might be a native JDBC transaction), with the JMS transaction committing right after the main transaction.(c)
My jms-configuration file contains only this:
<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" ref="url"/>
<property name="userName" ref="username"/>
<property name="password" ref="password"/>
</bean>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="connectionFactory"/>
<property name="defaultDestinationName" value="SomeQueue"/>
<property name="sessionTransacted" value="true"/>
</bean>
After that I try to test it in simple way:
Case A:
#Transactional
public void sendMessageTransactionalErr(Object message, List<String> queueDestinationNames) throws Exception {
sender.sendMessage(message, queueDestinationNames);
throw new Exception("FatalException!");
}
Case B:
#Transactional
public void sendMessageTransactionalOK(Object message, List<String> queueDestinationNames) throws Exception {
sender.sendMessage(message, queueDestinationNames);
}
But in both cases after request execution message is send to queue. Even if JDBC transaction rolled back, JMS transaction commit succesfull.
What should I do to make it work as I need to?
You need to use a transaction manager that handles BOTH your JMS transaction and database transaction. Your JMS transaction is separate from the database transaction.
I don't recall exactly, but when I had this problem I created an instance of org.springframework.jms.connection.JmsTransactionManager. Create a JTA transaction manager and make sure your it is aware of this AND the database transaction manager.
Use #Transactional("jtaTransactionManager") for the annotation. I may have tried Bitronix or JOTM for this use case.
See Spring Integration and Transaction with JMS and DB
Reference: http://www.javaworld.com/article/2077963/open-source-tools/distributed-transactions-in-spring--with-and-without-xa.html?page=2
I have a legacy code that use the TransactionManager to obtain access to the transaction to associate synchronization objects to the transaction afterCommit.
When I migrate to Spring 3, the recommended transaction manager to my solution is WebSphereUowTransactionManager, in truth, I feel that it is only a factory to the real Transaction Manager. But this transaction manager always return null in the method getTransactionManager().
I'm using EJB's 2.1 (legacy, remember?) with CMT.
My configuration is Spring 3.1.2.RELEASE, Hibernate 3.6.8.Final, Websphere 6.1.0.43, my beans are:
<bean
id="transactionManager"
class="org.springframework.transaction.jta.WebSphereUowTransactionManager" />
<bean
name="auditContextManager"
class="... my class ...">
<property name="transactionManager">
<bean factory-bean="transactionManager" factory-method="getTransactionManager" />
</property>
</bean>
My hibernate configuration is:
<hibernate-configuration>
<session-factory>
<property name="hibernate.jdbc.fetch_size">200</property>
<property name="hibernate.jdbc.use_get_generated_keys">true</property>
<property name="hibernate.bytecode.use_reflection_optimizer">true</property>
<property name="hibernate.connection.datasource">java:comp/env/jdbc/ORDS</property>
<property name="hibernate.dialect">org.hibernate.dialect.Oracle9iDialect</property>
<property name="hibernate.max_fetch_depth">3</property>
<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
<property name="hibernate.transaction.factory_class">org.hibernate.transaction.CMTTransactionFactory</property>
<property name="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.WebSphereExtendedJTATransactionLookup</property>
<property name="hibernate.show_sql">false</property>
... too much mappings to show here ...
</session-factory>
</hibernate-configuration>
And my bean auditContextManager has always transactionManager set to null.
It seems to me that WebSphereUowTransactionManager do not expose Transaction Manager intentionally. Is this alright ?
There is any way so I can get the Transaction Manager ? Since WebSphereUowTransactionManager is not really the transaction manager, but only a transaction manager factory.
It is not a factory for the TransactionManager but, as the name suggest, the UOWManager. It uses the Websphere native API for managing transactions (which has broader support for certain things than the plain JTA api).
So there isn't going to be a TransactionManager it will always be null.
Basically if you want the transactionamanager you will have to do a JNDI lookup.
com.ibm.ws.Transaction.TransactionManagerFactory is the factory you should use to get the transaction manager .
We are upgrading our project from Spring 2.5.6 to 3.2.3 and Hibernate/JPA to 4.2.3.
In spring-ds.xml for transaction management we replaced original below config
<bean id="transactionManager"
class="org.springframework.transaction.jta.WebSphereUowTransactionManager">
<!-- This property is specifically required for JMS -->
<property name="transactionManager" ref="baseTransactionManager" />
</bean>
<bean id="baseTransactionManager"
class="org.springframework.transaction.jta.WebSphereTransactionManagerFactoryBean" />
<tx:annotation-driven transaction-manager="transactionManager" />
to below as WebSphereTransactionManagerFactoryBean class is superseded in latest WAS :
<bean id="transactionManager"
class="org.springframework.transaction.jta.WebSphereUowTransactionManager" />
and JMS msg listener config looks like below :
<bean id="xxtMsgListenerContainer"
class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="jmsxxConnectionFactory" />
<property name="destination" ref="jmsxxQueue" />
<property name="messageListener" ref="xxMessageListener" />
<property name="transactionManager" ref="transactionManager" />
<property name="taskExecutor" ref="taskExecutor" />
</bean>
With above config we are getting below error in WAS logs :
Setup of JMS message listener invoker failed for destination
queue://xxQueue?busName=zzBus' - trying to recover. Cause: No JTA UserTransactionavailable - programmatic PlatformTransactionManager.getTransaction usage not supported
Is there any other config/property required to upgrade to spring 3.2.3 ? or to config WebSphereUowTransactionManager do we need to set any property ?
In case you are using Hibernate in your application, the actual Hibernate version used can be the root cause of the problem.
We spent half a day debugging it (on a WebSphere box), and then found that indeed it was the hibernate version upgrade (from 4.2.7.Final to 4.2.12.Final) which caused issue, not the JMS configuration.
UPDATE: It seems that Hibernate includes transaction-api jboss-transaction-api_1.1_spec which was not compatible with the one present on Websphere. Simply excluding this from hibernate resolved the issue.
on the DefaultMessageListenerContainer, try setting the sessionTransacted property to true. this should enable transaction support with WebSphere
The error happens because you have used JTA transaction manager, while your connection factory is not XA capable. Essentially injected implementation of ConnectionFactory does not implement JTA interfaces. Thus transaction manager isn't able of enrolling a message consumption into a new instance of UserTransaction.
In other to fix this issues the one needs to use XA capable ConnectionFactory, or other non-jta transaction manager like Spring's JmsTransactionManager.
I am trying to use Spring to send a message to a queue. It works fine when I don't try to enable transaction handling. However, when I add transaction handling the message doesn't seem to send to the appropriate queue. All i add is a #Transactional attribute on the method and the following to the application context.
<tx:annotation-driven/>
<bean id="transactionManager" class="org.springframework.jms.connection.JmsTransactionManager">
<property name="connectionFactory" ref="connectionFactory"/>
</bean>