Reputation: 93
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?
Upvotes: 1
Views: 2060
Reputation: 1256
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.
Upvotes: 3