在我的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()”时,我担心会得到“分离实体”异常。
答案 0 :(得分:0)
唯一让人想到的事情(如果你原谅双关语)就是如果你从bean中的另一个方法调用cancelReservation()
,那么我不确定是否会观察到事务注释。注释最终通过召唤一个拦截器起作用,我相信拦截器只适用于不同类之间的调用(这是我应该检查的东西)。
因此,如果bean上有一个非事务性方法,它调用事务方法,那么在调用事务方法时就不会启动事务。
我可能完全错了。我会去阅读一些规范,然后再回复你。
编辑:我读过规范,它提醒我J2EE规范是什么灾难区。可怕的。但是,有关事务的部分似乎暗示事务属性仅适用于对EJB业务接口的调用。我相信在bean内部从一个方法到另一个方法的调用不会被认为是通过业务接口,即使被调用的方法是该接口的一部分。因此,您不会指望它们会吸引交易。你可以尝试的东西是通过界面路由它们;没有很好的方法可以做到这一点,但你应该能够像这样注入业务接口自引用:
public class RegistrationStateful implements RegistrationStatefulRemote {
@EJB
private RegistrationStatefulRemote self;
然后,您可以将@PreDestroy方法更改为:
@PreDestroy
public void destroy() {
self.cancelReservation();
}
我认为这应该算作正常的业务接口调用,事务等等。
我从来没有尝试过这个,所以这可能是完全垃圾。如果您尝试一下,请告诉我它是如何工作的!