The mysteriously necessary sessionTransacted=true

I’ve encountered this before, but just ran into it again: Despite suggestions to the contrary, it is necessary (at least with Spring 2.5.5, ActiveMQ 5.1.0, and JBoss 4.2.2.GA) to set sessionTransacted=true in the DefaultMessageListenerContainer even when it’s set up to connect to an external JTA transaction manager. If I set sessionTransacted=true, then when my messageListener throws a RuntimeException, the message is rolled back onto the queue; if I don’t, it doesn’t.

This has been documented elsewhere regarding Atomikos, but not ActiveMQ. I’ve posted a question to the Spring Remoting and JMS forum. We’ll see what comes of it!

15 thoughts on “The mysteriously necessary sessionTransacted=true

  1. This is one of the dark corners of the JMS / JTA integration, you can blame it on both specs (and even a bit on the EJB spec which also contains some pieces of the puzzle) that are extremely unclear and vague in this regard.

    The Spring documentation is absolutely correct but needs to be carefully read a few times to make sense.

    Setting sessionTransacted=true is used to configure JMS-transacted (ie: local JMS transactions) DefaultMessageListenerContainer. It is basically used by Spring to feed the 1st parameter of this method:

    http://java.sun.com/j2ee/1.4/docs/api/javax/jms/Connection.html#createSession(boolean,%20int)

    When the JMS resource is configured for XA transaction mode, the application server’s javax.jms.Connection object will ignore this parameter as documented in Spring’s JMSTemplate:

    http://opensource.objectsbydesign.com/spring-1.1.4/org/springframework/jms/core/JmsTemplate.html#setSessionTransacted(boolean)

    This is logical because the Session returned by the application server will use an underlying XASession object to perform the work and creating this XASession object from an XAConnection object takes no parameter:

    http://java.sun.com/j2ee/1.4/docs/api/javax/jms/XAConnection.html#createXASession()

    Again this makes sense as to guarantee transactional semantics you MUST have transactions and auto-acknowledge.

    It took me some time to digest all that but the result is that with BTM, no matter what you set in sessionTransacted you will get transactional semantics when using the session inside a JTA transaction.

  2. Ludovic,
    It still seems to me that the Spring manual leaves out any hint of needing to set sessionTransacted=true when using a JtaTransactionManager. Even a one-sentence addition would help — maybe something like “Some JMS implementations require that sessionTransacted be set to true even when connecting to a JTA transaction manager, to achieve transactional semantics.”

  3. That would be wrong for at least these two reasons:

    First, this is not a JMS implementation problem but a JMS XA pool problem.

    Second, any JMS XA pool that requires Spring’s sessionTransacted to be set to any value is not EJB / JTA spec compliant.

    Do you think they should document non spec compliant behaviors ?

  4. “any JMS XA pool that requires Spring’s sessionTransacted to be set to any value is not EJB / JTA spec compliant.”

    So is it ActiveMQ that is requiring sessionTransacted to be set to true when it shouldn’t need to be?

    (Thank you for your patience with me as I try to understand)

  5. I know this is really confusing but no, the problem is not in ActiveMQ.

    A brief background info:

    – The JMS XAConnectionFactory implementation is the responsibility of the JMS implementation under the JMS spec.

    – The TransactionManager and UserTransaction implementations are the responsibility of the transaction manager under the JTA spec.

    – The JMS XA pool (that wraps XAConnectionFactory as ConnectionFactory) is the responsibility of the application server under the EJB spec.

    The problem of Spring’s sessionTransacted falls under the JMS XA pool’s responsibility: the pool should ensure this value is meaningless in the context of a JTA transaction.

    In a classic application server, you do not have to be concerned about this as it implements all 3 specs.

    With standalone transaction managers, this can cause headaches as to be of any use, such transaction manager also has to provide some XA pooling mechanism or else, you would have access to the JTA API but no single database or JMS server could participate in JTA transactions.

  6. Hi,

    First: in the XASession javadoc it says that isTransacted() is always true for these sessions. So this supports the need for sessionTransacted=true.

    Second: if you create a session with sessionTransacted=false then you should NOT get a transacted session, since you might be doing explicit acknowledgment in your code. This contradicts transacted sessions…

    In other words, you risk breaking the client-side coding contract (and semantics) of explicit acknowledgment if you return an XA session merely because of a JTA transaction being present.

    Third: Transacted session in JMS are characterized by the acknowledgment coinciding with transaction commit. See http://www.atomikos.com/Publications/ReliableJmsWithTransactions for more information. This is the case for local as well as JTA transactions. Again, this supports sessionTransacted=true.

    Fourth: returning XA (or non-XA) sessions merely based on JTA transaction context (for the calling thread) is very dangerous as it might lead to unexpected behavior (suppose the JTA transaction times out etc…).

    Of course, this is just my interpretation but I think it is consistent in all its aspects (which is more than you can say from the combination of all specs involved:-)

    Guy
    BTW I work for Atomikos :-)

  7. Guy,
    What do you make of Denis’s reply at the Spring Forum (starting with his quote of me, “I still don’t understand why the sessionTransacted setting should make any difference…”)

    I am coming to see, though, that differences of opinion are likely to not be simply resolved as I had originally hoped:

    * The Spring guys probably think it’s clear that sessionTransacted should be a don’t-care value when you’re getting an XASession, so they don’t document having to set sessionTransacted=true when using a JtaTransactionManager;
    * The JMS broker guys (Atomikos, ActiveMQ, etc.) think it’s clear that sessionTranacted *should* matter, and program accordingly;
    * Poor users like me (sad violin music in background) have to learn for ourselves what has to be done. : )

  8. According to traditional J2EE docs such as WebLogic’s, the sessionTransacted parameter (corresponding to the standard JMS createSession method) has to be *false* in order to get a JTA-enabled session:

    http://edocs.bea.com/wls/docs92/jms/trans.html#wp1025537

    The preceding section on native JMS transaction states that: “JTA user transactions are ignored by JMS transacted sessions.”

    In other words, JTA participation on WebLogic only works with sessionTransacted=false. If it’s set to true, you always get a native JMS-transacted Session that happens to ignore JTA transaction completely…

    This is why we use sessionTransacted=false as default in Spring. Point taken that we should add a warning to our JMS section in the reference docs: Always check with your JMS provider / XA provider.

    Juergen

  9. The usage of sessionTransacted=”true” vs setting a jmsTransactionManager property for DefaultMessageListenerContainer(DMLC)

    We use JBoss 4.2 server. In dev env, we use a local JBoss Queue and there are no redeliveries. In the test env, we use a remote weblogic queue.

    We have a MDP wired using spring into a DMLC. The message falls into queue, onMessage processes it and dumps to a db. We do not use XA since when we got the app, HibernateTransactionManager took care of db transactions. The onMessage has a try/catch block wherein first we try the db insert and if it fails we throw a JMSException in the catch and it works akin to a global transaction.

    What we noticed is that when sessionTransacted=true it works well on dev env(with a local jboss queue), but in the test env(with a remote weblogic queues, the JMS messages were redelivered. But when we took out sessionTransacted=”true” and set spring JmsTransactionManager instead, the redeliveries stopped in the test env(our problem was fixed)

    The spring doc says that one can use either sessionTransacted=”true” or set an external JmsTransactionManager. So why did only the setting of an external JmsTransactionManager work in this case?

  10. Neal,
    You seem to be speaking of the redeliveries as if they are a problem, and you were glad when the redeliveries stopped. Am I understanding correctly?

    But if your message processing encounters an exception and the transaction is rolled back, you would want the message to be redelivered, right? (Unless you just want to lose the message in this case, which is certainly not the behavior I need!)

    The setup you describe is Hibernate local transactions plus JMS local transactions (managed by the external JmsTransactionManager). What XA gives you that your setup doesn’t have is coordinated commit/rollback of your db and JMS transactions. In your setup, a db transaction could roll back after the JMS transaction had committed or vice versa, leaving the system in an inconsistent state.

    This is not insurmountable; a page on ActiveMQ’s website sketches an alternative to XA where you have your application logic detect duplicate messages in this case.

    Hope this helps. (I wrote up a timely response several days ago but accidentally closed my browser without sending, and was so deflated by the waste of time that it took me until today to respond again. ;)

  11. An additional note on this issue: for our 3.6 release of TransactionsEssentials we will (by default) ignore the transacted flag, always returning an XA session. This release is expected in August 2009.

    Best
    Guy

  12. in our application we are using weblogic with spring jms, we also enable both spring transaction manger and session transacted true we are getting lot of duplicate messages still we wondering for root cause

  13. As per my understanding from spring documentation. We have to use sessionTransacted=true only in case of jms local transactions or standalone applications, but in case of XA.
    I am using jboss6.1.0 and we have configured the hornetQ with XA and my application has spring 4 where we defined the jmsTemplate to drop a message into a queue and DefaultMessageListenerContainer to listen the messages from the queue and the JTA Transaction has been configured by defining the bean definition for JTATransactionManager.
    We have configured sessionTransacted=true for the jmsTemplate bean, but not for the DefaultMessageListenerContainer bean.
    We have a transaction on a method businessProcessing() where we do DB inserts and also drop a message into a Queue. We have come across any issue where the message is being dropped and the listener read the message, even before the transaction on the method businessProcessing() was committed, and the listener in processing message has to retrieve the data from the DB to perform some business logic where the data is not available, because the transaction has not yet commited on the other end.
    I am trying to figure out issue, what caused the message to drop before the transaction has committed.
    Please give some advice , if you have any solutions available for such problems.

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.