Наследует от | @ApplicationException | Транзакция помечена для отката |
---|---|---|
Exception | Нет аннотации | Нет |
Exception | rollback = true | Да |
Exception | rollback = false | Нет |
RuntimeException | Нет аннотации | Да |
RuntimeException | rollback = true | Да |
RuntimeException | rollback = false | Нет |
Транзакции, управляемые компонентом. С помощью CMT вы указываете контейнеру сделать разграничение транзакций, просто указав атрибут транзакции и используя контекст сеанса или исключения для пометки транзакции для отката. В некоторых случаях декларативный CMT не может обеспечить необходимую детализацию разграничения (например, метод не может генерировать более одной транзакции). Для того чтобы решить эту проблему, EJB предлагает программный способ управления разграничением транзакций с помощью BMT. BMT позволяет явно управлять границами транзакций (начало, фиксация, откат) с использованием JTA.
Для того чтобы отключить разграничение по умолчанию CMT и переключиться в режим BMT, компонент просто должен использовать аннотацию @javax.ejb.TransactionManagement (или XML-эквивалент в файле ejb-jar.xml) следующим образом:
@Stateless
@TransactionManagement(TransactionManagementType.BEAN)
public class ItemEJB {…}
С помощью разграничения BMT приложение запрашивает транзакции, контейнер EJB создает физическую транзакцию и заботится о низкоуровневых деталях. Кроме того, он не распространяет транзакции от одного ВМТ к другому.
Основной интерфейс, используемый для проведения ВМТ, — javax.transaction.UserTransaction. Он позволяет компоненту разграничивать транзакции, получает их состояние, задает тайм-аут и т. д. В контейнере EJB создается экземпляр типа UserTransaction, который становится доступным благодаря внедрению зависимостей, поиску JNDI или контексту SessionContext (с помощью метода SessionContext.getUserTransaction()). Этот API описывается в табл. 9.5.
Метод | Описание |
---|---|
begin | Начинает новую транзакцию и связывает ее с текущим потоком |
commit | Фиксирует транзакцию, связанную с текущим потоком |
rollback | Откатывает транзакцию, связанную с текущим потоком |
setRollbackOnly | Помечает транзакцию для отката |
getStatus | Получает текущее состояние транзакции |
setTransactionTimeout | Изменяет тайм-аут текущих транзакций |
В листинге 9.6 показано, как разработать компонент BMT. Прежде всего мы получаем ссылку на объект типа UserTransaction с использованием внедрения через аннотацию @Resource. Метод OneItemSold() начинает транзакцию, выполняет обработку, а затем, в зависимости от бизнес-логики, совершает фиксацию или откат транзакции. Отмечу также, что транзакция помечается для отката в блоке catch (для удобства чтения я упростил обработку исключений).
@Stateless
@TransactionManagement(TransactionManagementType.BEAN)
public class InventoryEJB {
··@PersistenceContext(unitName = "chapter09PU")
··private EntityManager em;
··@Resource
··private UserTransaction ut;
··public void oneItemSold(Item item) {
····try {
······ut.begin();
······item.decreaseAvailableStock();
······sendShippingMessage();
······if (inventoryLevel(item) == 0)
········ut.rollback();
······else
········ut.commit();
······} catch (Exception e) {
······ut.rollback();
····}
····sendInventoryAlert();
··}
}
Разница с CMT, показанным в листинге 9.3, заключается в том, что с CMT контейнер запускает транзакцию до исполнения метода и фиксирует ее сразу после его отработки. С BMT, показанным в листинге 9.6, вы вручную определяете границы транзакции внутри самого метода.
Поддержка транзакций в Managed Beans