@Transactionalメソッドは@Transactionalアノテーションなしで別のメソッドを呼び出しますか?


88

としてマークされたServiceクラスのメソッドを見ました@Transactionalが、同じクラス内の、としてマークされていない他のメソッドも呼び出していました@Transactional

別のメソッドを呼び出すと、アプリケーションがDBへの別の接続を開いたり、親トランザクションを一時停止したりすることを意味しますか?

アノテーション付きの別のメソッドによって呼び出されるアノテーションなしのメソッドのデフォルトの動作は何@Transactionalですか?

回答:


116

@Transactionalトランザクションブロック内でメソッドを呼び出すと、親トランザクションは新しいメソッドに進みます。親メソッド(with @Transactional)からの同じ接続と、呼び出されたメソッドで発生した例外(なし)@Transactionalは、トランザクション定義で構成されているようにトランザクションをロールバックします。

同じインスタンス内の@Transactionalメソッドからアノテーション付きのメソッドを呼び出す場合@Transactional、呼び出されたメソッドのトランザクション動作はトランザクションに影響を与えません。ただし、トランザクション定義を持つ別のメソッドからトランザクション定義を持つメソッドを呼び出し、それらが異なるインスタンスにある場合、呼び出されるメソッドのコードは、呼び出されるメソッドで指定されたトランザクション定義に従います。

詳細については、Springトランザクションドキュメントの宣言型トランザクション管理のセクションを参照してください。

Spring宣言型トランザクションモデルはAOPプロキシを使用します。したがって、AOPプロキシはトランザクションの作成を担当します。AOPプロキシは、インスタンス内のメソッドがインスタンスの外部から呼び出された場合にのみアクティブになります。


それは春のデフォルトの動作ですか?
goe 2011年

はい。これはデフォルトの動作です。
Arun P Johny 2011年

2
@Tomaszはい。ただし、別の@Transactionalメソッドから呼び出されたメソッドでトランザクション伝播を変更しても効果がないことにも注意してください。
フィル2011年

1
@Tomasz、それは私が言ったことwill follow the transaction definitions given in the called methodでした。ただし、呼び出しが同じオブジェクトインスタンスからのものである場合、トランザクションの保守を担当するaopプロキシを介して呼び出しが伝播されないため、効果はありません。
Arun P Johny 2011年

5
@Filip、それは完全には正しくありません。@Transactional異なるオブジェクト/インスタンスから定義を使用してメソッドを呼び出すと、呼び出し元のメソッドの@Transactional属性が異なっていても、呼び出されたメソッドはそれ自体のトランザクション定義に従います。
Arun P Johny 2011年

23
  • これは、個別のメソッドを呼び出すと、アプリケーションがDBへの個別の接続を開いたり、親トランザクションを一時停止したりすることを意味しますか?

それは伝播レベルに依存します。可能なすべてのレベルは次のとおりです

たとえば、伝播レベルがNESTEDの場合、現在のトランザクションは「一時停止」され、新しいトランザクションが作成されます(注:ネストされたトランザクションの実際の作成は、特定のトランザクションマネージャーでのみ機能します)。

  • @Transactionalアノテーションを持つ別のメソッドによって呼び出されるアノテーションのないメソッドのデフォルトの動作は何ですか?

デフォルトの伝播レベル(「動作」と呼ばれるもの)はREQUIREDです。@Transactionalアノテーションが付いた「内部」メソッドが呼び出された場合(またはXMLを介して宣言的にトランザクションされた場合)、同じトランザクション内で実行されます。たとえば、「何も新しいものは作成されません」。


アノテーションのないNOT_SUPPORTEDのサブコールはどうですか?NOT_Supportedを継承しますか、それともREQUREDがデフォルトであるため、新しいトランザクションを開きましたか?例:f1.call(){f2()}、注釈はf1の場合はNOT_SUPPORTED、f2の場合はnon。
デイブ

8

@Transactionalはトランザクション境界(開始/終了)をマークしますが、トランザクション自体はスレッドにバインドされます。トランザクションが開始されると、元のメソッドが返され、トランザクションがコミット/ロールバックされるまで、メソッド呼び出し全体に伝播されます。

@Transactionalアノテーションを持つ別のメソッドが呼び出された場合、伝播はそのアノテーションの伝播属性に依存します。


3つの答えはある程度矛盾しており、どちらがより正確かはわかりません。
エリック王

1
@EricWang今日このシナリオをテストしたことを共有したかったのですが、Arun P Johny による回答(コメント付き)は、この内部呼び出しのシナリオに最も正確です。
Vinay Vissh

3

内部メソッドに@Transactionalアノテーションが付けられていない場合、内部メソッドは外部メソッドに影響します。

内部メソッドにも@Transactionalアノテーションが付けられている場合REQUIRES_NEW、次のようになります。

...
@Autowired
private TestDAO testDAO;

@Autowired
private SomeBean someBean;

@Override
@Transactional(propagation=Propagation.REQUIRED)
public void outerMethod(User user) {
  testDAO.insertUser(user);
  try{
    someBean.innerMethod();
  } catch(RuntimeException e){
    // handle exception
  }
}


@Override
@Transactional(propagation=Propagation.REQUIRES_NEW)
public void innerMethod() {
  throw new RuntimeException("Rollback this transaction!");
}

内部メソッドにはアノテーションが付けられREQUIRES_NEW、RuntimeExceptionがスローされるため、トランザクションはロールバックに設定されますが、外部トランザクションには影響しません。外側のトランザクションは、内側のトランザクションが開始されると一時停止され、内側のトランザクションが終了すると再開されます。これらは互いに独立して実行されるため、外部トランザクションは正常にコミットされる場合があります。


1
初心者のために明確にするために、innerMethod()はouterMethod()とは異なるBean(別名Spring管理のJavaオブジェクト)上にある必要があると確信しています。それらが両方とも同じBean上にある場合、innerMethodがアノテーションで宣言されたTransactional動作を実際に使用するとは思わない。むしろ、outerMethod()宣言で宣言されているものを使用します。これは、春はそれの@Transactional注釈(のために使用されているAOP、どのように処理するかであるdocs.spring.io/spring/docs/3.0.x/spring-framework-reference/...
johnsimer
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.