0

概要 :

誰かが、開発者に例外のキャッチを強制することを避けるために、EntityExistsException が RuntimeException であると判断しました。この例外を回避してトランザクションをロールバックする方法は何ですか? EntityExistsException をキャッチすると、トランザクションは既にコンテナーによってロールバックされています... imho EntityExistsException は実際にはランタイム例外ではありません...そのような例外から回復できるはずです...ランタイム例外をキャッチする方法とアプリケーション例外を再スローします (チェックあり)。2 つのステートレス セッション Bean でテストされました。

詳細に :

私の例では、2 つのステートレス セッション Bean があります。

最初のセッション Bean は新しいトランザクションを開始します (REQUIRES_NEW) Bean は新しいエンティティを永続化します。次に、2 番目のステートレス セッション Bean が呼び出されます。

2 番目のセッション Bean は、トランザクションを開始した Bean によって呼び出されたため、新しいトランザクション (MANDATORY または REQUIRED) を開始しません。JPA は javax.persistence.EntityExistsException をスローしますが、実際にスローされるのは javax.ejb.EJBTransactionRolledbackException です。(これは単なる例です。RuntimeException をスローするメソッドはトランザクションをロールバックします。エンティティ存在例外を人為的に生成する方法を見つけました...)

ApplicationException を作成しました。デフォルトでは、ApplicationException がトランザクションをロールバックしないことがわかっています。

2 番目の ejb では、EJBTransactionRolledbackException (または EntityExistsException) をキャッチし、代わりにアプリケーション例外をスローします。トランザクションをロールバックしないでください。

2 番目の Bean がトランザクションに参加し、トランザクションが常にロールバックされるため、トランザクションに影響を与えます。

RuntimeException (EntityExistsException) が原因でそのトランザクションがロールバックされるのを回避する方法はありますか? EntityExistsException または EJBTransactionRolledbackException をキャッチし、アプリケーション例外を再スローします。

2番目のトランザクションにも新しいトランザクション(REQUIRES_NEW)が必要な場合、これは回避できます。しかし、私はそれを避けて、1 つのトランザクションのみを保持したいと考えています...

openejb からのロギング:

最初のセッション Bean と最初のメソッド

DEBUG 10-07 12:20:53,002 (Log4jLogStream.java:debug:81) -TX NotSupported: 一時停止するトランザクションはありません DEBUG 10-07 12:20:53,002 (Log4jLogStream.java:debug:81) -TX RequiresNew: トランザクションはありませんDEBUG 10-07 12:20:53,003 (Log4jLogStream.java:debug:81) を一時停止するには -TX RequiresNew:トランザクション org.apache.geronimo.transaction.manager.TransactionImpl@25ef757f を開始しまし た 1 持続後 1 スリープ 10

2 番目のセッション Bean と 2 番目のメソッド

DEBUG 10-07 12:21:03,009 (Log4jLogStream.java:debug:81) - bcmc-core.be.awl.clearing.bcmc.core.utils.TestService001 DEBUG 10-07 12:21:03,011 ( Log4jLogStream.java:debug:81) - メソッド create の呼び出しを終了しました。戻り値:proxy=be.awl.clearing.bcmc.core.utils.TestService001;deployment=bcmc-core.be.awl.clearing.bcmc.core.utils.TestService001;pk=null DEBUG 10-07 12:21: 03,012 (Log4jLogStream.java:debug:81) - bcmc-core.be.awl.clearing.bcmc.core.utils.TestService001 でメソッド writeToDatabase を呼び出し、ID null DEBUG 10-07 12:21:03,014 (Log4jLogStream.java:debug :81) -TX NotSupported: 中断されたトランザクション org.apache.geronimo.transaction.manager.TransactionImpl@25ef757f DEBUG 10-07 12:21:03,014 (Log4jLogStream.java:debug:81) -TX NotSupported: トランザクション org.apache を再開しています。 geronimo.transaction.manager.

DEBUG 10-07 12:21:03,018 (Log4jLogStream.java:debug:85) - Bean インスタンス ビジネス メソッドでシステム例外が発生しました: 同じ識別子値を持つ別のオブジェクトが既にセッションに関連付けられていました: [be.awl.clearing .bcmc.core.model.parameters.RepBcmcParam#be.awl.clearing.bcmc.core.model.parameters.RepBcmcParamId@aed63ef8] javax.persistence.EntityExistsException: 同じ識別子値を持つ別のオブジェクトが既にセッションに関連付けられていました: [be.awl.clearing.bcmc.core.model.parameters.RepBcmcParam#be.awl.clearing.bcmc.core.model.parameters.RepBcmcParamId@aed63ef8] ...

DEBUG 10-07 12:21:03,020 (Log4jLogStream.java:debug:81) - 例外 org.apache.openejb.core.transaction.TransactionRolledbackException でメソッド writeToDatabase の呼び出しを終了しました: トランザクションは、Bean が非検出に遭遇したためだけにロールバックとマークされました。 - アプリケーション例外 :javax.persistence.EntityExistsException : 同じ識別子値を持つ別のオブジェクトが既にセッションに関連付けられていました: [be.awl.clearing.bcmc.core.model.parameters.RepBcmcParam#be.awl.clearing.bcmc. core.model.parameters.RepBcmcParamId@aed63ef8]

DEBUG 10-07 12:21:03,021 (Log4jLogStream.java:debug:85) - Bean インスタンスのビジネス メソッドでシステム例外が発生しました: Bean で非アプリケーション例外:javax.persistence が発生したため、トランザクションはロールバックのみとマークされました。 EntityExistsException : 同じ識別子値を持つ別のオブジェクトが既にセッションに関連付けられていました: [be.awl.clearing.bcmc.core.model.parameters.RepBcmcParam#be.awl.clearing.bcmc.core.model.parameters.RepBcmcParamId@ aed63ef8] javax.ejb.EJBTransactionRolledbackException: Bean が非アプリケーション例外を検出したためだけに、トランザクションはロールバックとマークされました:javax.persistence.EntityExistsException: 同じ識別子値を持つ別のオブジェクトが既にセッションに関連付けられていました: [be.awl .clearing.bcmc.core.model.parameters.RepBcmcParam#be.awl.clearing.bcmc.core.model.parameters.RepBcmcParamId@aed63ef8] ... 原因: javax.persistence.EntityExistsException: 同じ識別子値を持つ別のオブジェクトがすでにセッションに関連付けられていました: [be.awl.clearing.bcmc.core.model.parameters.RepBcmcParam# be.awl.clearing.bcmc.core.model.parameters.RepBcmcParamId@aed63ef8] ...

DEBUG 10-07 12:21:03,022 (Log4jLogStream.java:debug:81) -TX RequiresNew: トランザクション org.apache.geronimo.transaction.manager.TransactionImpl@25ef757f のロールバック

DEBUG 10-07 12:21:03,024 (Log4jLogStream.java:debug:81) -TX RequiresNew: 再開するトランザクションはありません

DEBUG 10-07 12:21:03,024 (Log4jLogStream.java:debug:81) - 例外 java.rmi.RemoteException でメソッド writeToDatabase の呼び出しを終了しました: Bean で非アプリケーション例外が発生しました。ネストされた例外は次のとおりです: javax.ejb.EJBTransactionRolledbackException: Bean が非アプリケーション例外を検出したためだけに、トランザクションはロールバックとマークされました:javax.persistence.EntityExistsException: 同じ識別子値を持つ別のオブジェクトが既にセッションに関連付けられていました: [be .awl.clearing.bcmc.core.model.parameters.RepBcmcParam#be.awl.clearing.bcmc.core.model.parameters.RepBcmcParamId@aed63ef8] スレッド「Thread-49」での例外 javax.ejb.EJBException: Bean が検出されました非適用例外; ネストされた例外は: javax.ejb.EJBTransactionRolledbackException:

最初のセッション Bean :

@Stateless(name = "bcmc-core.be.awl.clearing.bcmc.core.utils.TestService")
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public class TestServiceImpl implements TestService {
@PersistenceContext(unitName = "bcmc-core")
private EntityManager em;       
@Override
public void writeToDatabase() {         
    try {

        RepBcmcParam bcmcParam = new RepBcmcParam();
        RepBcmcParamId bcmcParamId = new RepBcmcParamId();
        bcmcParamId.setProcname("procname");
        bcmcParamId.setParid("parid");
        Date date = new Date();
        bcmcParamId.setDtbeg(date);
        bcmcParam.setId(bcmcParamId);
        bcmcParam.setParval("parval");
        System.out.println("1");
        em.persist(bcmcParam);
        System.out.println("after persist 1 sleeping 10");
        try {
            Thread.currentThread().sleep(10000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        TestService001 testService001 = net.atos.xa.resourcelocator.ResourceLocator.lookup(TestService001.class);
        testService001.writeToDatabase(date);
        System.out.println("after write to database 2 sleeping 10");
        try {
            Thread.currentThread().sleep(10000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }           
    } catch(BcmcDuplicateException be) {
        System.out.println("facade");
    }                   
}

2 番目のセッション Bean :

@Stateless(name = "bcmc-core.be.awl.clearing.bcmc.core.utils.TestService001")
@TransactionAttribute(TransactionAttributeType.MANDATORY)
public class TestService001Impl implements TestService001 { 
@PersistenceContext(unitName = "bcmc-core")
private EntityManager em;   
private static final Logger LOGGER = Logger.getLogger(Constants.APP_NAME);  
@Resource
private SessionContext context;
    try {           
        System.out.println("get rollback only " + context.getRollbackOnly());
        RepBcmcParam bcmcParam = new RepBcmcParam();
        RepBcmcParamId bcmcParamId = new RepBcmcParamId();
        bcmcParamId.setProcname("procname");
        bcmcParamId.setParid("parid");
        bcmcParamId.setDtbeg(date);         
        //bcmcParamId.setDtbeg(new Date());
        bcmcParam.setId(bcmcParamId);
        bcmcParam.setParval("parval");
        System.out.println("2");
        em.persist(bcmcParam);
        System.out.println("get rollback only " + context.getRollbackOnly());
        try {
            System.out.println("1 sec");
            Thread.currentThread().sleep(1000);             
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }           

    } catch(EJBTransactionRolledbackException e) {
        System.out.println("get rollback only " + context.getRollbackOnly());
        throw new BcmcDuplicateException();
    }
}
4

2 に答える 2

1

クライアントがシステム例外 (非 @ApplicationException RuntimeException) をキャッチして、トランザクションがロールバックされる前にそれをアプリケーション例外に変換する方法はありません。唯一の選択肢は、何らかの方法で EJB を調整することです。最初にアプリケーション例外をスローするように変更するか、キャッチ/再スローを行うインターセプターを追加するか、システム例外をアプリケーション例外に変更します (アノテーションまたは XML を介して)。 )。

于 2013-07-12T10:50:45.730 に答える
0

ここで一歩戻って....最初のビーンがすでに同じオブジェクトを保持しているのに、なぜ2番目のビーンが同じオブジェクトを保持したいのですか..そしてそれも同じトランザクションで? コンテナーがこの例外を処理する方法をいじる前に、元のソリューションを再考する必要があるのではないでしょうか?

あなたの問題に戻って、あなたの Application 例外は、ひょっとして RuntimeException のサブクラスですか? また、このようにしなければならない場合、この例外でトランザクションを手動でコミットできますか?

于 2013-07-10T12:24:04.193 に答える