EJB 3.1 TransactionAttributeType.REQUIRES_NEW и setRollbackOnly - PullRequest
4 голосов
/ 15 февраля 2012

Пожалуйста, помогите мне разобраться с транзакциями в EJB 3.1. Я использую GlassFish v3 и имею следующую ситуацию:

@Stateless
@LocalBean
public class BeanA {

    @Inject BeanB bean; /* which has no TransactionAttribute set */
    @Resource SessionContext context;

    public void run() {
        ...
        for (...) {
            process(someValue);
        }
    }

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void process(String someValue) {

        try {

            SomeEntity entity = bean.getEntity(someValue);
            entity.setSomeProperty("anotherValue");

            ...

        } catch(CustomException e)  {
            this.context.setRollbackOnly();
        }
    }

}

BeanA.run вызывается из сервлета. Я хочу рассматривать каждую итерацию как отдельную транзакцию. Я думал, что с помощью TransactionAttributeType.REQUIRES_NEW это можно понять, но я получаю исключение javax.ejb.EJBTransactionRolledbackException на последующих итерациях beanB после вызова setRollbackOnly. Странно то, что когда я перемещаю все, кроме run (), в новый BeanC и вызываю beanC.process, он работает. Что мне не хватает? Кто-нибудь может пролить свет на то, почему это работает так, как работает?

Edit: Если подумать: это потому, что контейнер не перехватывает вызовы методов в том же EJB? (что казалось бы разумным)

Редактировать 2: Да, нашел ответ здесь: EJB-транзакции в локальных вызовах методов (хотя я должен был знать ответ, чтобы найти его:))

Ответы [ 2 ]

4 голосов
/ 16 февраля 2012

Нашел ответ здесь: Транзакции EJB в локальных вызовах методов

Вкратце: контейнер не перехватывает вызовы локальных методов, поэтому setRollbackOnly пометил единственную транзакцию для отката, объяснив исключения.

0 голосов
/ 18 апреля 2018

Старый вопрос, но ради полноты ...

Действительно, аннотации типа @TransactionAttribute не обрабатываются при вызове непосредственно в классе.Это происходит потому, что вы вызываете его напрямую, как в процедурной функции.Он не проходит жизненный цикл EJB (включая перехватчики).

Хотя есть способ сделать это.Вам нужно внедрить собственный класс и использовать эту ссылку:

// Bean A

@Resource SessionContext context;

public void run() {
    ...
    for (...) {
       context.getBusinessObject(BeanA.class).process(someValue);
    }
}

Таким образом, он создаст процесс @TransactionAttribute.
Хотя это работает, я не уверен, что это хороший дизайн.

...