GlassFish 2.1中的EJB TransactionRequiredException

时间:2011-07-24 11:45:51

标签: java exception transactions ejb

在我的Stateful bean中,我有以下几行:

@Stateful(mappedName = "ejb/RegistrationBean")
@StatefulTimeout(unit = TimeUnit.MINUTES, value = 30)
@TransactionManagement(value=TransactionManagementType.CONTAINER)
public class RegistrationStateful implements RegistrationStatefulRemote {

    @PersistenceContext
    EntityManager em;

    private List<Event> reservedSessions = new ArrayList<Event>();
    private boolean madePayment = false;

    ...
    @TransactionAttribute(TransactionAttributeType.REQUIRED)
    private void cancelReservation() {
        if (reservedSessions.size() != 0) {
            Teacher theTeacher;
            for (Event session : reservedSessions) {
                if ((theTeacher = session.teacher) == null) theTeacher = bestTeacher.teacher;
                theTeacher = em.merge(theTeacher) //The exception is thrown here

                //Make changes to theTeacher

                em.flush(); //The exception is also thrown here
            }

            //Clear the reservedSessions list
            reservedSessions.clear();
        }
    }

    @Remove
    public void endRegistration() {}

    @PreDestroy
    public void destroy() {
        //Cancel outstanding reservations if payment has not been made
        if (!madePayment) cancelReservation(); 
    }
}

em.merge(someEntity)行会引发TransactionRequiredException。有人可以告诉我为什么会这样吗?我想到TransactionAttribute.REQUIRED,如果没有活动的事务,将自动创建一个事务。我尝试使用em.joinTransaction(),但它会抛出相同的Exception。我是这次交易的初学者。如果有人能向我解释这一点,我将非常感激。

更新:我想添加更多信息

Stateful bean实际上还具有以下功能:

@TransactionAttribute(TransactionAttributeType.REQUIRED)
private void reserveSession(List<Event> sessions) throws ReservationException {
    //Reserve the sessions
    Teacher theTeacher;

    for (Event session : sessions) {
        if ((theTeacher = session.teacher) == null) theTeacher = bestTeacher.teacher;
        theTeacher = em.merge(theTeacher);

        //Make changes to theTeacher            

        em.flush();
    }   
}

流程如下:用户告诉我他的空闲时间,我为他预留了一些座位。之后,我向他展示了他的预订座位,他可以选择付款或取消预订。

reserved()函数按预期完美运行,但cancelReservation()没有。

更新2:我昨晚通过注释掉“@TransactionAttribute(TransactionAttributeType.REQUIRED)”,“em.merge(theTeacher)”和“em.flush()”来修复问题“在”cancelReservation()“函数中。结果很完美。如果切断这些线条会安全吗?当我首先使用“em.merge()”时,我担心会得到“分离实体”异常。

1 个答案:

答案 0 :(得分:0)

唯一让人想到的事情(如果你原谅双关语)就是如果你从bean中的另一个方法调用cancelReservation(),那么我不确定是否会观察到事务注释。注释最终通过召唤一个拦截器起作用,我相信拦截器只适用于不同类之间的调用(这是我应该检查的东西)。

因此,如果bean上有一个非事务性方法,它调用事务方法,那么在调用事务方法时就不会启动事务。

我可能完全错了。我会去阅读一些规范,然后再回复你。

编辑:我读过规范,它提醒我J2EE规范是什么灾难区。可怕的。但是,有关事务的部分似乎暗示事务属性仅适用于对EJB业务接口的调用。我相信在bean内部从一个方法到另一个方法的调用不会被认为是通过业务接口,即使被调用的方法是该接口的一部分。因此,您不会指望它们会吸引交易。

你可以尝试的东西是通过界面路由它们;没有很好的方法可以做到这一点,但你应该能够像这样注入业务接口自引用:

public class RegistrationStateful implements RegistrationStatefulRemote {
    @EJB
    private RegistrationStatefulRemote self;

然后,您可以将@PreDestroy方法更改为:

@PreDestroy
public void destroy() {
    self.cancelReservation();
}

我认为这应该算作正常的业务接口调用,事务等等。

我从来没有尝试过这个,所以这可能是完全垃圾。如果您尝试一下,请告诉我它是如何工作的!