Чтобы применить один из этих шести атрибутов разграничения для вашего сессионного компонента, вы должны использовать аннотацию @javax.ejb.TransactionAttribute или дескриптор развертывания (установите элемент
@Stateless
@TransactionAttribute(TransactionAttributeType.SUPPORTS)
public class ItemEJB {
··@PersistenceContext(unitName = "chapter09PU")
··private EntityManager em;
··@Inject
··private InventoryEJB inventory;
··public List
····TypedQuery
····return query.getResultList();
··}
··@TransactionAttribute(TransactionAttributeType.REQUIRED)
··public Book createBook(Book book) {
····em.persist(book);
····inventory.addItem(book);
····returnbook;
··}
}
Контекст транзакций клиента не распространяется при асинхронном вызове метода (@Asynchronous). MDB поддерживает только атрибуты REQUIRES и NOT_SUPPORTED, что описано в главе 13.
Маркировка CMT для отката транзакции
Вы видели, что контейнер EJB разграничивает операции автоматически и вызывает операции начала, фиксации и отката от вашего имени. Но как разработчик вы, возможно, захотите предотвратить фиксируемую транзакцию, если произойдет какая-либо ошибка или сработает бизнес-правило. Важно подчеркнуть, что компонент CMT не допускает явного отката транзакций. Вместо этого вам нужно использовать контекст EJB (см. раздел «Внедрение зависимостей» главы 7) для того, чтобы проинформировать контейнер об откате.
Как вы можете видеть в листинге 9.3, InventoryEJB содержит метод oneItemSold(), который получает доступ к базе данных через менеджер хранения и посылает JMS-сообщение для того, чтобы сообщить отправляющей компании, что предмет продан и должен быть доставлен. Если количество доступных предметов равно нулю, методу необходимо явно откатить транзакцию. Чтобы сделать это, компонент, не сохраняющий состояние, сначала должен получить контекст SessionContext с помощью внедрения зависимостей, а затем вызвать его метод setRollbackOnly(). Вызов этого метода не выполняет откат транзакции непосредственно, вместо этого в контейнере устанавливается флаг, который сигнализирует о том, что следует сделать откат транзакции в момент ее завершения. Только сессионные компоненты с разграничением с помощью CMT могут использовать этот метод (сессионные компоненты BMT откатывают транзакцию непосредственно, что показано в пункте «Транзакции, управляемые компонентом» далее).
@Stateless
public class InventoryEJB {
··@PersistenceContext(unitName = "chapter09PU")
··private EntityManager em;
··@Resource
··private SessionContext ctx;
··public void oneItemSold(Item item) {
····item.decreaseAvailableStock();
····sendShippingMessage();
····if (inventoryLevel(item) == 0)
······ctx.setRollbackOnly();
··}
}
Аналогично компонент может вызвать метод SessionContext.getRollbackOnly(), который возвращает переменную типа boolean, чтобы определить, помечена ли текущая транзакция для отката.