如何处理丢弃的有状态会话bean

时间:2014-01-27 13:51:04

标签: java-ee ejb-3.0 stateful-session-bean

偶尔,我的有状态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中捕获异常并避免丢弃?如果我发现异常,交易状态如何?我是否必须进行一些手动回滚?

感谢。

1 个答案:

答案 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();
{