偶尔,我的有状态EJB(3.0)中的操作会抛出SQLException(超时已过期)。它发生的方法:
@PersistenceContext(unitName = "MYPU")
EntityManager entityManager;
List<Message> list;
public List<Message> newSearch() {
// do some unsignificant things
loadFirstPage();
}
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public List<Message> loadFirstPage() {
CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
cq.select(cq.from(entityClass));
list = getEntityManager().createQuery(cq).getResultList();
}
此SFSB已注入另一个类:
private MyBean myBean;
@EJB(name = "messageloaderbean")
public void setMyBean(MyBean myBean) {
this.myBean = myBean;
}
然后它的引用在调用类中作为参数传递:
public class Controller{
private MyBean myBean;
public Controller(MyBean myBean){
this.myBean = myBean;
}
public void methodThatCallsMyBean(){
this.myBean.newSearch();
}
}
如果抛出运行时异常(如SQLException),现在会发生什么,因为我使用CMT并且根据EJB规范,容器首先回滚事务,然后丢弃EJB。然后,如果我想在丢弃之后再次使用这个EJB,我会得到一个javax.ejb.NoSuchEJBException: Bean has been deleted
。
这有意义,因为bean被丢弃了,但是如何获得对新的有状态bean的引用呢?
我是否应该在SFSB中捕获异常并避免丢弃?如果我发现异常,交易状态如何?我是否必须进行一些手动回滚?
感谢。
答案 0 :(得分:1)
但是如何获得对新的有状态bean的引用?
容器在bean的生命周期开始时注入代理,因此在这种情况下,每个新的staless bean实例只会注入一次statefull引用。 另一种方法是通过JNDI查找获得引用,但这会更麻烦。
我是否应该在SFSB中捕获异常并避免丢弃?
是的,我认为这是最好的解决方案。
我是否必须进行一些手动回滚?
是。当Container拦截RuntimeException时,它标记事务以进行回滚。我需要保持此行为,必须手动标记当前事务。有几种选择:
a)抛出一个Application Exception并用@AnnotationException(rollback = true)注释它。在这种情况下,容器将标记事务以进行回滚而不丢弃bean实例。
b)通过SessionContext.setRollbackOnly()方法标记事务。
//inject a SessionConetext instance
@Resource
SessionContext session;
try {
//your code goes here
} catch (RuntimeException e)
//log the error
session.setRollbackOnly();
{