3

私の質問は、トランザクションと例外に関連しています

要件:

データベース テーブルに挿入するレコードが 10 個あります。すべてのレコードを挿入した後、別のテーブルにデータを挿入します。したがって、2 番目のテーブルへの挿入が失敗した場合は、そのレコードをロールバックしたいと考えています。

元。一度に 10 人分の現金振込 (1 つの口座から口座へ) を処理するとします。

擬似コード: ------------- EJB メソッドの開始

for(int i = 0; i < TransferRecords.length; i++)
{
    try
    {
          //Deduct cash from TransferRecord.accountFrom --- Includes use of Hibernate Session
          //Add cash in TransferRecord.accountTo -- Includes use of Hibernate Session
     } catch(AppException exception)
     {
            //Rollback the transaction only for this particular transfer (i)
            // But here when I go for next record it says session is closed
     }
}

---------EJB メソッドの終了

ここでは @ApplicaitonException(rollback=true) アノテーションで AppException を作成しています。

必要な機能は次のとおりです。TransferRecord (たとえば 2) でトランザクションが失敗した場合でも、データをレコード 0、レコード 1、レコード 3、レコード 4 (など... レコード 2 ではなく) にコミットする必要があります。

ただし、ここでの問題は、TransferRecord 2 が失敗し、TransferRecord 3 に移動すると、「Session Closed」エラーが発生することです。

私の疑問は次のとおりです。1.これは正しいアプローチですか?または、EJB 2 の外部で (TransferRecord ごとに) for ループを実行する必要があります。セッションが閉じられていないが、トランザクションがロールバックされていることを確認するにはどうすればよいですか?

前もって感謝します。

EJB3、Hibernate 3.x、Jboss 4.2.x を使用しており、Container Managed Transaction を使用しています。

4

3 に答える 3

3

これは正しいアプローチですか?

いいえ、CMT では、メソッドはトランザクション単位です。したがって、ここでは、すべてTransferRecordが同じ一意のトランザクションで処理されます。

ところで、トランザクションをどのようにロールバックしますか? を伝播しますか、RuntimeExceptionそれとも を呼び出しsetRollbackOnly()ますか? 私はただ興味があります。

または、EJB の外部で (各 TransferRecord に対して) for ループを実行する必要がありますか?

なぜ外に?それを強制するものは何もありません。それぞれTransferRecordを独自のトランザクションで処理する場合は、それらを別のEJB メソッドに渡す必要があります (以下のコードは、この回答に触発されています)。

// supposing processRecords is defined on MyStatelessRemote1 and process defined on MyStatelessLocal1
@Stateless
@TransationAttribute(TransactionAttributeType.NOT_SUPPORTED)
public class MyStatelessBean1 implements MyStatelessLocal1, MyStatelessRemote1 {
    @EJB
    private MyStatelessLocal1 myBean;

    public void processRecords(List<TransferRecord> objs) {
        // No transactional stuff so no need for a transaction here
        for(Object obj : objs) {
            this.myBean.process(obj);
        }
    }

    @TransationAttribute(TransactionAttributeType.REQUIRES_NEW)
    public void process(TransferRecord transferRecord) {
        // Transactional stuff performed in its own transaction
        // ...
    }
}

セッションが閉じられていないが、トランザクションがロールバックされていることを確認するにはどうすればよいですか (特定の失敗したトランザクションの場合のみ)

その部分をカバーしたと思います。

于 2010-01-08T19:24:55.177 に答える
1

ここにある唯一のオプションは、Bean の外側のループのコンテナー管理トランザクションの代わりにユーザートランザクションを使用して、Bean に入るたびに、関連付けられたトランザクションと接続 (基本的にセッション) を持つ新しいエンティティマネージャーを取得することです。

于 2010-01-08T19:30:25.713 に答える
0

2 つの別々のトランザクションを作成できると思います。1 つ目は TransferRecord(1) 用であり (すべてが正常に完了したらコミットを実行します)、次にすべての TransferRecord(i+1) 用に別の TX を開始します。

別のアプローチは、セーブポイントを使用して、そのセーブポイントを過ぎたすべてをロールバックして破棄できるようにすることです (ただし、私は最初のアプローチを好みます)。

よろしく。

于 2010-01-08T17:55:56.370 に答える