8
votes

What's the best way to accomplish the following?

  • @MessageDriven bean does some work on database
  • on failure, I want to roll back the DB transaction
  • but I also want the JMS message NOT to be redelivered, i.e., don't re-try.

I can think of a few ways that might work. Are there any others, and which is the best?

  • use @TransactionManagement(type=BEAN) and UserTransaction, and explicitly roll back after catching exception. e.g.:

    catch (Exception e) { e.printStackTrace(); utx.rollback(); }

  • Use container-managed transactions, specify @TransactionAttribute(value=NOT_SUPPORTED) on onMessage and then delegate DB activity to a separate method with @TransactionAttribute(value=REQUIRED).

  • Leave the transaction handling alone and re-configure the retry property in the server. I'm using Glassfish 3.1.1, and I'm not exactly sure how to set this.

  • Leave everything alone and explicitly check the message for re-delivery in the onMessage body, and exit out if re-delivered. (message.getJMSRedelivered()?)

What has worked well out there? Is there a standard/best-practice way for dealing with this?

2

2 Answers

8
votes

Simplest and most portable approach is use @TransactionAttribute(value=NOT_SUPPORTED) on onMessage() as you state and to move the DB work to another bean with @TransactionAttribute(REQUIRES_NEW)

Be careful about the separate method approach as this will not work. In a JMS MDB the onMessage() method is the only method where @TransactionAttribute can be used.

2
votes

Personally I never do any work in the MDB, but dispatch immediately to an (injected) session bean.

This bean then does the DB work. It either starts a new transaction, or I catch any exception from the bean and log it (but don't let it propogate, so no redelivery).

This also has the advantage that the business logic is easly reusable from other places.