Tuesday November 29, 2005
Transactions and JMS I started to talk about JMS thence I might write a few sentences about transactions. Very often use case is that you deliver message and then this message is stored in database. How we can solve this. Should we use JTA for this?
I hope that reader knows that you mustn't use global transaction for consumer and producers. Why? Because, having all producers and all consumers participate in one global transaction would defeat the purpose of using a loosely coupled asynchronous messaging environment. JMS transactions follow the convention os separating the send operations from the receive operations. Which ways do we have for transactions with JMS?
UserTransaction txt = (UserTransaction) ctx.lookup("UserTransaction");
txt.begin();
// make JDBC stuff and send message
txt.commit();
public void onMessage(Message aMessage) {
try{
if (aMessage instanceof ObjectMessage){
// process message
Order order = (Order)((ObjectMessage) aMessage).getObject();
Connection conn = getDS().getConnection();
// insert Order in DB
...................
}else{
logger.log(Level.SEVERE,"Only object messages are supported.");
}
}catch(SQLException ex){
context.setRollbackOnly();
}
}
I encountered one issue with this approach in Sun Aplication server. Messages are redelivered again and again. It means that you can flood your server with many messages. BTW, it's good test of Sun App server for DOS attack :-). I know that Jboss allows to setup of number of redelivering but I can't find it for Sun App server. Therefore, I suggest to use a little bit approach, throw EJB exception. What's happened when the database will be offline? Under container-managed transaction demarcation, upon receiving a runtime exception (EJBException extends Runtime exception) from a MDB the container roll-backs the container-started transaction and the message is delivered in dead queue. Below is same sample that throws EJBException.
public void onMessage(Message aMessage) {
try{
if (aMessage instanceof ObjectMessage){
// process message
Order order = (Order)((ObjectMessage) aMessage).getObject();
Connection conn = getDS().getConnection();
// insert Order in DB
...................
}else{
logger.log(Level.SEVERE,"Only object messages are supported.");
}
}catch(SQLException ex){
throw new EJBException(ex);
}
}