2017-05-08 7 views
1

私はedit(E entity)関数をループで呼び出すbatchEdit(List<E> entity)を持っていますが、各edit()は独自のトランザクションを持っているので、失敗した編集は良い編集をロールバックしません。私は現在、それはそうのように実装している:それはすべてのEJBの境界を通過しないのでthis stackoverflow discussionによるとEJBで複数のトランザクションを取得するきれいで標準的な方法は何ですか?

オプション1

@Stateless 
@TransactionManagement(value = TransactionManagementType.CONTAINER) 
public class Service<E> { 

    @Resource 
    private SessionContext context; 

    @Override 
    @TransactionAttribute(value = TransactionAttributeType.REQUIRES_NEW) 
    public E edit(E entity) { 
     //edit code 
    } 

    @Override 
    public List<E> bulkEdit(List<E> entities) { 
     for(E entity : entities){ 
      //case 1: Regular edit, Does not create a new transaction! 
      //edit(entity); 

      //case 2: Hacky edit, creates a new transaction 
      context.getBusinessObject(Service.class).editPersistNulls(entity); 
     } 
    } 
} 

@TransactionAttributeは、私の場合1には無視されるので、batchEdit()通話edit()としてそれが注釈されていない場合。ケース2のcontext.getBusinessObject()関数を使用してBeanの参照を取得すると、TransactionManagementアノテーションが機能しますが、そのすべてを処理するのは本当に変です。

私が持っている他のオプションは、Bean管理トランザクションに変更することです

オプション2:

@TransactionManagement(value = TransactionManagementType.BEAN) 

しかし、その後、私は、「JPAマジック」失い、どこでもトランザクションを管理する必要があります。私のチームの他の人がそれを通過したいとは思わないので、これを行うためのより良い、または標準的な方法があれば、どんな洞察も高く評価されます。

私たちはOpenJPAとEJBを使用していますが、私たちはJPA標準に近づいています。

答えて

0

"ハッキー"は見る人の目の前です。 context.getBusinessObjectはこの種のことを行うことができるように正確に存在します。

@Stateless 
public class BulkService<E> { 

    @EJB 
    private Service<E> service; 

    public List<E> bulkEdit(List<E> entities) { 
     for(E entity : entities) { 
      service.editPersistNulls(entity); 
     } 
    } 

} 

あなたの包括的なトランザクションがタイムアウトすることができますように、しかし大きなエンティティリストの用心:

代替は、第二のクラスを使用することです。

Java EE 7に準拠したサーバー実装を使用している場合は、JSR-352 Batch Applicationsサポートの使用を検討してください。

+0

興味深い。私たちはgetBusinessObjectソリューションを使い終わった。その唯一の厄介な部分は、Beanのクラス自体ではなく、Beanのインタフェースが必要であるということです。 Beanのクラス自体を渡すと、 "Component has such interface:"という結果が出力されますが、インターフェースを渡すと動作します。 – GuitarStrum

+0

インターフェイスを完全に削除すると、クラス名を使用できます。あまり頻繁ではない、さまざまな実装を計画している場合は、EJB上のインタフェースのみを使用してください。 –

+0

私はチームでそれを実行します。潜在的なテストのためのインターフェースがまだありませんでしたが、インターフェースを渡すことは大きなリファクタリングになるでしょう。 – GuitarStrum

1

EJBを単独で注入できます。

@Stateless 
public class Service<E> { 

    @EJB 
    private Service<E> self; 

    @TransactionAttribute(REQUIRES_NEW) 
    public void edit(E entity) { 
     // ... 
    } 

    @TransactionAttribute(NOT_SUPPORTED) 
    public void bulkEdit(List<E> entities) { 
     for (E entity : entities) { 
      self.edit(entity); 
     } 
    } 
} 

これは@Asynchronousにする方がよいでしょう。それはより速いです。

@Stateless 
public class Service<E> { 

    @EJB 
    private Service<E> self; 

    public void edit(E entity) { 
     // ... 
    } 

    @Asynchronous 
    @TransactionAttribute(REQUIRES_NEW) 
    public void asyncEdit(E entity) { 
     // ... 
    } 

    @TransactionAttribute(NOT_SUPPORTED) 
    public void bulkEdit(List<E> entities) { 
     for (E entity : entities) { 
      self.asyncEdit(entity); 
     } 
    } 
} 

それはまた同じトランザクションに滞在する必要があり、もちろん他のサービスから呼び出される可能性があるとして、潜在的に不要なREQUIRES_NEWトランザクション属性から自由にオリジナルedit()方法を保持します。 @Asynchronousの場合は、すべてのコールで新しいトランザクションが必要になることが理にかなっています。

+0

私は非同期メソッドを2回(またはそれ以上)短期間で呼び出すとどうなりますか?オーバーフローが発生するまで、呼び出しが積み重なっていますか? – kaiser

+0

@kaiser Nope。それぞれは別のスレッドで実行されます。 – BalusC

+0

最後の質問が1つあります。 REQUIRED_NEWを使用します。呼び出し元の関数はNOT_SUPPORTEDを持つので、REQUIRED属性は同じではないでしょうか? – kaiser

関連する問題