それはタイトルが言うように正確ではないが、近くに。これらの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
。しかし、これはそうではないように思われます。
デバッグツールでオーバー行くときは、私が見ていることはこれです:
- とき
doSomeWork
のMainWorkerBean
開始、新しいトランザクションが作成されます - ときに
methodB
開始されると、トランザクションマネージャは、適切にそれがセーブポイントと手を初期化TransactionInterceptor
- ときに
methodA
開始し、トランザクションマネージャは、見ているPropagation.REQUIRED
セーブポイントの知識を持たない再度、実際のJDBCトランザクションにクリーンな参照、出再び、手
例外がスローされたときに、この手段TransactionStatus::hasSavepoint
リターンfalse
、全体のグローバル・トランザクションのロールバックにどのリード、その失われたとして回復し、さらなるステップが良いようですが、私はの回復を書いたので、私の実際のコードは、ロールバック(の知識を持ちませんそれ)。
今のところ、私は変更を検討することはできませんBeanA
にの取引をPropagation.NESTED
。確かに、それのようなルックスは、私はより多くの地元のロールバックを持つことができるようになるだろうが、私がそれを理解し、春には2つのセーブポイントを持つことになります、とだけロールバックするので、あまりにもローカルになるだろうBeanA
ではないセーブポイント、BeanB
「私として、1をDのように。
私が欠けている何か他のものは、との内部取引はなるだろう設定オプションとして、そこにあるPropagation.REQUIRED
それはセーブポイント内で実行されていることを考えると、セーブポイントへのロールバックではなく、全体のこと?
今、私たちは春の4.3.24を使用しているが、私はすでに彼らのコードをクロールと私はアップグレードが私を助けるとは思わないので、関連するすべての変更を見つけることができません。
このバグチケットに説明したように:https://github.com/spring-projects/spring-framework/issues/11234
説明した状況での春バージョン<5.0、のために、グローバル・トランザクションは「ロールバックのみ」に設定されています。
この取引では、私はいくつかのタスクを処理しています。エラーが一つのタスク中に発生した場合、私はので、私はPROPAGATION_NESTEDの伝播に別のトランザクション境界にタスク処理をラップし、トランザクション全体がロールバックされないようにします。
タスクの処理中に、コールがPROPAGATION_REQUIREDのトランザクション境界で定義されている既存のサービスメソッドに行われた場合、問題が来ます。根本的な接続原因これらのメソッドからスローされるすべての実行時例外ではなく、現在の親トランザクションのネストされた伝播を尊重するよりも、ロールバック専用としてマークされます。
[...]
春のフレームワーク5.0の時点では、ネストされたトランザクションはもうグローバルトランザクションにそれを適用していない、セーブポイントへのロールバックに自分のロールバックのみの状態を解決します。
古いバージョンでは、推奨される回避策は切り替えることがある
globalRollbackOnParticipationFailure
にfalse
、このようなシナリオで。
問題を再現するときしかし、たとえSpring5のために、私は)(ネストされたトランザクションはmethodBのcatchブロックで行うすべてのものを含め、ロールバックすることができることに、気づきました。あなたの回復のコードでは、どのようなあなたの回復ルックス等に応じて、)(methodB内部で動作しない場合がありますので。methodA()がトランザクションでなかった場合、それは起こりません。ただ、何か気をつけます。
ここで発見されるいくつかの詳細:https://github.com/spring-projects/spring-framework/issues/8135