简体   繁体   中英

Correct usage of transactions in JMS and EJB

I wonder how to use JMS transactions correctly inside an EJB container. I found this code, that sends messages using JMS in a stateless bean:

@Stateless
public class SendEventsBean {

  private static final Logger log = Logger.getLogger(SendEventsBean.class);

  @Resource(mappedName = "jms/MyConnectionFactory")
  private ConnectionFactory jmsConnectionFactory;

  @Resource(mappedName = "jms/myApp/MyQueue")
  private Queue queue;

  public void sendEvent() {
    Connection jmsConnection = null;
    try {
        connection = jmsConnectionFactory.createConnection();
        Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
        MessageProducer producer = session.createProducer(queue);
        MyObj obj = new MyObj(1, "Foo");
        ObjectMessage myObjMsg = session.createObjectMessage(obj);
        producer.send(myObjMsg);
    } catch (JMSException jmxEx) {
        log.error("Couldn't send JMS message: ", jmsEx);
    }finally{
        if (jmsConnection != null) {
            try {
                jmsConnection.close();
            }catch(JMSException ex) {
               log.warn("Couldn't close JMSConnection: ", ex);
            }
        }
    }
  }

(from When should I close a JMS connection that was created in a stateless session bean? )

At default the transactions are container managed with transaction attribute 'required'. Suppose a client calls sendEvent() directly, so that the transaction starts at the beginning and ends at the end of sendEvent() (-> a commit is executed at the very end of the method). Isn't it wrong to close the connection (jmsConnection.close()) BEFORE the commit occurs at the very end of the method?

Furthermore I'm wondering how setting the transactional attribute and setting true/false at createSession() interacts.

Does it make sense setting createSession(true,...) if there is already a transaction started by the container (using container managed transactions)? Does this create a new transaction just for JMS messages (and not for DB also) inside the JTA transaction?

And with createSession(false, ...) am I right, that messages are nevertheless transactional because of the transaction started by the container?

Isn't it wrong to close the connection (jmsConnection.close()) BEFORE the commit occurs at the very end of the method?

No. Closing connections has got nothing to do with commit within a JTA transaction (which is the case here, it being an ejb with CMT). It is just proper and essential cleanup. Note these are connections returned by the container and the underlying transaction manager knows how to work with the resource to commit the transactions. Same goes for JDBC connections as well.

Does it make sense setting createSession(true,...) if there is already a transaction started by the container (using container managed transactions)?

For Weblogic, you should definitely be using non transacted sessions. But what is important to use XA connection factories for your JMS connections.

http://docs.oracle.com/cd/E11035_01/wls100/jms/trans.html#wp1031645 http://www.informit.com/articles/article.aspx?p=26137&seqNum=8

However articles related to JBOSS suggests setting the createSession(true...) as a good practise even within a CMT ejb

https://developer.jboss.org/thread/213629?tstart=0&_sscc=t http://www.coderanch.com/t/606786/EJB-JEE/java/EJB-CMT-sending-JMS-message

Irrespective of the setting, JCA/XA based connection factories have to be used compulsorily.

And with createSession(false, ...) am I right, that messages are nevertheless transactional because of the transaction started by the container?

No. As mentioned above, you will have to use XA connection factories.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM