2012-06-27 66 views
1

首先,this解決方案不適合我,因爲我無法更改持久性單元。JPA:如何使用與JTA EntityManager進行交易?

我的問題是,我使用JTA EntityManager的,但我需要整整一個用例類似交易:

public boolean saveWithResult(PointsValidityPeriod pointsValidityPeriod) 
{ 
    //TODO use transaction here 
    super.save(pointsValidityPeriod); 

    if (updatePrevious(pointsValidityPeriod.getValidFrom()) != 1) 
    { 
     logger.error("Update of Period was not possible, because UPDATE returned no single result."); 

     return false; 
    } 

    pointsValidityPeriodEvent.fire(pointsValidityPeriod); 

    return true; 
} 

保存方法(我不能改變):

public void save(T entity) 
{ 
    getEntityManager().persist(entity); 
} 

你會看到,有一個保存調用,但是如果更新出錯,這個保存必須回退,那麼我該如何實現呢?有任何想法嗎?

+0

JTA的重點在於管理交易。你在哪個環境中執行你的應用程序?具有EJB的應用程序服務器?然後使用EJB來劃分交易:這是他們的主要觀點。 –

+0

是的,我們在JBoss中使用EJB。 – Bevor

+0

默認情況下,EJB是事務性的。默認情況下,EJB方法中的所有代碼都是在事務中執行的。 –

回答

0

我有解決方案,但我不知道爲什麼這個工程。也許有人可以向我解釋。 在我的支持bean中有保存方法。有2個實體。 getEntity()是支持bean使用的當前實體,currentValidityPeriod是該實體的另一個實例,該實體持有實體的最新數據庫狀態,由currentValidityPeriod = pointsValidityService.findCurrent()提取。 findCurrent()是隻是其中執行TypedQuery的方法:

public PointsValidityPeriod findCurrent() 
{ 
    TypedQuery<PointsValidityPeriod> validityPeriodQuery = entityManager.createNamedQuery(PointsValidityPeriod.FindCurrent, PointsValidityPeriod.class); 

    return validityPeriodQuery.getSingleResult(); 
} 

這是由視圖調用保存方法。如您所見,我只將當前實體傳遞給服務保存方法。在之前的實體(currentValidityPeriod)中,我設置了另一個值。

@Override 
public void save() 
{  
    Date validFrom = new DateTime(DateTimeZone.forID("Europe/Vienna")).toDate(); 
    getEntity().setValidFrom(validFrom); 

    currentValidityPeriod.setValidThru(validFrom); 

    pointsValidityService.save(getEntity()); 

    addSavedSuccessfullyMessage(); 
} 

這是服務方法將被調用:

@Override 
public void save(PointsValidityPeriod pointsValidityPeriod) 
{ 
    super.save(pointsValidityPeriod); 
} 

...和超類的保存方法:

public void save(T entity) 
{ 
    getEntityManager().persist(entity); 
} 

爲什麼實體管理器持久化新的實體和更新舊的?我只是通過ONE實體到實體管理器。雖然這是預期的行爲,但我想知道爲什麼這會起作用。

+1

當您處於事務中時,JPA提供程序需要在事務提交時同步處於'managed'狀態的實體狀態與數據庫。換句話說,如果你在事務中從數據庫中獲取實體並且改變它的狀態,在tx commit期間它會自動對這個實體執行'更新'。 –

1

這一切都取決於您的方法事務註釋。如果您沒有,那麼默認情況下,事務邊界設置爲業務方法,如JB所指。

因此,整個方法是一個事務。通常情況下,save方法的交易管理很重要(如果是REQUIREDREQUIRES_NEW),但在這種情況下,您正在進行本地方法調用 - 而不是業務方法調用,因此任何用於save方法的交易管理設置在這裏不適用。

因此,如果update失敗可以上自動事務回滾爲鹼(如果它是一個EntityManager呼叫其生成回滾的Tx除外)也可以手動注入SessionContext和線之間在其上調用setRollbackOnly(),東西:

@Resource 
SessionContext ctx; 

public boolean saveWithResult(PointsValidityPeriod pointsValidityPeriod) 
{ 
    // ... 
    if (updatePrevious(pointsValidityPeriod.getValidFrom()) != 1) 
    { 
     // ... 
     ctx.setRollbackOnly(); 
     // ... 
    } 
} 
+0

不幸的是我不能這樣做。 Eclipse向我展示了「沒有bean有資格注入注入點[JSR-299§5.2.1]」,並且最終在啓動JBoss時導致異常:org.jboss.weld.exceptions.DeploymentException:WELD-001408 Unsatisfied類型爲[SessionContext]的依賴關係具有限定符[@Default]在注入點[[field] @Inject – Bevor

+0

註解不應該是@Resource?有關如何從EJB獲取SessionContext,請參閱http://javahowto.blogspot.fr/2006/06/4-ways-to-get-ejbcontext-in-ejb-3.html。 –

+0

啊,當然是JB - '@ Resource'!抱歉的傢伙,太多的CDI讓我變成一個無聊的男孩! –