2014-01-27 35 views
1

現在,我的有狀態EJB(3.0)中的操作拋出SQLException(超時已過期)。的方法,它發生了:如何處理丟棄的有狀態會話bean

private MyBean myBean; 
@EJB(name = "messageloaderbean") 
public void setMyBean(MyBean myBean) { 
    this.myBean = myBean; 
} 

然後將其引用作爲參數調用類傳入:

@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已在其他類被注入

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

但是我怎樣才能得到一個新的有狀態bean的引用?

容器在bean的生命週期開始時注入代理,因此在這種情況下,每個新的staless bean實例都只注入一次statefull引用。 另一種方法是通過JNDI查找來獲取參考,但這樣做會更麻煩。

我是否應該在我的SFSB中捕獲異常並避免這種丟棄?

是的,我認爲這是最好的解決方案。

我必須做一些手動回滾嗎?

是的。當容器攔截RuntimeException時,它將事務標記爲回滾。我需要保持這種行爲,當前的交易必須手動標記。有幾種替代方法:

a)拋出應用程序異常並使用@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(); 
{