В главе 7 вы видели несколько примеров сессионных компонентов, аннотаций и интерфейсов, но еще не встречали ничего относящегося к транзакциям. В листинге 9.1 показан код сессионного компонента, не сохраняющего состояние и использующего CMT. Как вы можете видеть, здесь не добавляются дополнительные аннотации и не реализуются особые интерфейсы. EJB является транзакционным по своей природе. При конфигурации с помощью исключений применяются все значения по умолчанию для управления транзакциями (REQUIRED — это атрибут, используемый по умолчанию для управления транзакциями, что объясняется далее в этом разделе).
@Stateless
public class ItemEJB {
··@PersistenceContext(unitName = "chapter09PU")
··private EntityManager em;
··@Inject
··private InventoryEJB inventory;
··public List
····TypedQuery
····return query.getResultList();
··}
··public Book createBook(Book book) {
····em.persist(book);
····inventory.addItem(book);
····return book;
··}
}
Вы можете спросить, почему код в листинге 9.1 является транзакционным. Ответом станет контейнер. На рис. 9.5 показано, что происходит, когда клиент вызывает метод createBook(). Вызов клиента перехватывается контейнером, который проверяет непосредственно перед вызовом метода, связан ли контекст транзакции с вызовом. По умолчанию, если контекст транзакции недоступен, контейнер начинает новую транзакцию перед входом в метод, а затем вызывает метод createBook(). После выхода из метода контейнер автоматически фиксирует или откатывает транзакцию (если генерируется конкретный тип исключения, что вы увидите позже в разделе «Исключения и транзакции» данной главы).
Рис. 9.5. Обработка транзакции контейнером
Использование на шаге 4:addItem() контекста транзакции, применяемого на шаге 3:createBook() (контекст может как принадлежать клиенту, так и создаваться контейнером), является поведением по умолчанию. Финальная фиксация происходит, если успешно отработали оба метода. Такое поведение может быть изменено с помощью метаданных (аннотации или дескриптора развертывания XML). В зависимости от выбранного вами атрибута транзакции (REQUIRED, REQUIRES_NEW, SUPPORTS, MANDATORY, NOT_SUPPORTED или NEVER) вы можете повлиять на то, как контейнер разграничивает операции: при запуске клиентом метода, использующего транзакции, контейнер применяет транзакцию клиента, запускает метод в новой транзакции, запускает метод без транзакции или генерирует исключение. В табл. 9.3 определены атрибуты транзакции.