二重にネストされたトランザクションのロールバックは、セーブポイントをバイパス

M.プロホロフ:

それはタイトルが言うように正確ではないが、近くに。これらのSpring Beanを考えてみます。

@Bean
class BeanA {

    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = EvilException.class)
    public void methodA() {
        /* ... some actions */
        if (condition) {
            throw new EvilException();
        }
    }
}

@Bean
class BeanB {
    @Autowired private BeanA beanA;
    final int MAX_TRIES = 3;

    @Transactional(propagation = Propagation.NESTED)
    public void methodB() {
        // prepare to call Bean A
        try {
            beanA.methodA();
            /* maybe do some more things */
        }
        catch (EvilException e) {
           /* recover from evil */
        }
    }
}

@Bean
class MainWorkerBean {
    @Autowired private BeanB beanB;
    @Autowired private OtherBean otherBean;

    @Transactional(propagation = Propagation.REQUIRED)
    public void doSomeWork() {
        beanB.methodB();
        otherBean.doSomeWork();
    }
}

重要な注意:私はセーブポイントをサポートするJDBCトランザクションマネージャを使用しています。

とき私はこれを行うには期待していことで、EvilExceptionスローされ、トランザクションのBeanAこのセットアップで発生しロールバックされますが、セーブポイントが開始することにより作成されますmethodBしかし、これはそうではないように思われます。

デバッグツールでオーバー行くときは、私が見ていることはこれです:

  1. ときdoSomeWorkMainWorkerBean開始、新しいトランザクションが作成されます
  2. ときにmethodB開始されると、トランザクションマネージャは、適切にそれがセーブポイントと手を初期化TransactionInterceptor
  3. ときにmethodA開始し、トランザクションマネージャは、見ているPropagation.REQUIREDセーブポイントの知識を持たない再度、実際のJDBCトランザクションにクリーンな参照、出再び、手

例外がスローされたときに、この手段TransactionStatus::hasSavepointリターンfalse、全体のグローバル・トランザクションのロールバックにどのリード、その失われたとして回復し、さらなるステップが良いようですが、私はの回復を書いたので、私の実際のコードは、ロールバック(の知識を持ちませんそれ)。

今のところ、私は変更を検討することはできませんBeanAにの取引をPropagation.NESTED確かに、それのようなルックスは、私はより多くの地元のロールバックを持つことができるようになるだろうが、私がそれを理解し、春には2つのセーブポイントを持つことになります、とだけロールバックするので、あまりにもローカルになるだろうBeanAではないセーブポイント、BeanB「私として、1をDのように。

私が欠けている何か他のものは、との内部取引はなるだろう設定オプションとして、そこにあるPropagation.REQUIREDそれはセーブポイント内で実行されていることを考えると、セーブポイントへのロールバックではなく、全体のこと?

今、私たちは春の4.3.24を使用しているが、私はすでに彼らのコードをクロールと私はアップグレードが私を助けるとは思わないので、関連するすべての変更を見つけることができません。

tkruse:

このバグチケットに説明したように:https://github.com/spring-projects/spring-framework/issues/11234

説明した状況での春バージョン<5.0、のために、グローバル・トランザクションは「ロールバックのみ」に設定されています。

この取引では、私はいくつかのタスクを処理しています。エラーが一つのタスク中に発生した場合、私はので、私はPROPAGATION_NESTEDの伝播に別のトランザクション境界にタスク処理をラップし、トランザクション全体がロールバックされないようにします。

タスクの処理中に、コールがPROPAGATION_REQUIREDのトランザクション境界で定義されている既存のサービスメソッドに行われた場合、問題が来ます。根本的な接続原因これらのメソッドからスローされるすべての実行時例外ではなく、現在の親トランザクションのネストされた伝播を尊重するよりも、ロールバック専用としてマークされます。

[...]

春のフレームワーク5.0の時点では、ネストされたトランザクションはもうグローバルトランザクションにそれを適用していない、セーブポイントへのロールバックに自分のロールバックのみの状態を解決します。

古いバージョンでは、推奨される回避策は切り替えることがあるglobalRollbackOnParticipationFailurefalse、このようなシナリオで。

問題を再現するときしかし、たとえSpring5のために、私は)(ネストされたトランザクションはmethodBのcatchブロックで行うすべてのものを含め、ロールバックすることができることに、気づきました。あなたの回復のコードでは、どのようなあなたの回復ルックス等に応じて、)(methodB内部で動作しない場合がありますので。methodA()がトランザクションでなかった場合、それは起こりません。ただ、何か気をつけます。

ここで発見されるいくつかの詳細:https://github.com/spring-projects/spring-framework/issues/8135

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=326401&siteId=1