Транзакции @MessageDriven и семантика повторной доставки

Каков наилучший способ выполнить следующее?

  • Компонент @MessageDriven выполняет некоторую работу с базой данных
  • в случае неудачи я хочу откатить транзакцию БД
  • но я также хочу, чтобы сообщение JMS НЕ было доставлено повторно, т. Е. Не повторять попытку.

Я могу придумать несколько способов, которые могут работать. Есть ли другие и какие лучше?

  • используйте @TransactionManagement(type=BEAN) и UserTransaction и явно откатывайтесь после перехвата исключения. например.:

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

  • Используйте транзакции, управляемые контейнером, укажите @TransactionAttribute(value=NOT_SUPPORTED) в onMessage, а затем делегируйте действия БД отдельному методу с помощью @TransactionAttribute(value=REQUIRED).

  • Оставьте обработку транзакций в покое и перенастройте свойство повтора на сервере. Я использую Glassfish 3.1.1, и я не совсем уверен, как это установить.

  • Оставьте все в покое и явно проверьте сообщение на повторную доставку в теле onMessage и выйдите из него, если оно будет доставлено повторно. (message.getJMSRedelivered()?)

Что там хорошо сработало? Есть ли стандартный/лучший способ справиться с этим?


person wrschneider    schedule 31.12.2011    source источник


Ответы (2)


Самый простой и переносимый подход - использовать @TransactionAttribute(value=NOT_SUPPORTED) на onMessage(), как вы указали, и перенести работу с БД на другой компонент с помощью @TransactionAttribute(REQUIRES_NEW)

Будьте осторожны с подходом отдельного метода, так как это не сработает. В JMS MDB метод onMessage() является единственным методом, где можно использовать @TransactionAttribute.

person David Blevins    schedule 02.01.2012
comment
Спасибо, это сработало отлично. Примечание о @TransactionAttribute в MDB было ключевым — вы правы, вы можете аннотировать только onMessage. В конце концов я не аннотировал onMessage, но перенес логику в другой EJB с помощью REQUIRES_NEW. - person wrschneider; 05.01.2012
comment
Как примечание, он работает с дочерними компонентами EJB, аннотированными REQUIRED. - person apetrelli; 28.08.2013

Лично я никогда не выполняю никакой работы в MDB, а сразу отправляюсь в (внедренный) сессионный компонент.

Затем этот компонент выполняет работу с БД. Он либо запускает новую транзакцию, либо я перехватываю любое исключение из bean-компонента и регистрирую его (но не позволяю ему распространяться, поэтому повторная доставка невозможна).

Это также имеет то преимущество, что бизнес-логику легко повторно использовать из других мест.

person Mike Braun    schedule 02.01.2012