としてマークされたServiceクラスのメソッドを見ました@Transactional
が、同じクラス内の、としてマークされていない他のメソッドも呼び出していました@Transactional
。
別のメソッドを呼び出すと、アプリケーションがDBへの別の接続を開いたり、親トランザクションを一時停止したりすることを意味しますか?
アノテーション付きの別のメソッドによって呼び出されるアノテーションなしのメソッドのデフォルトの動作は何@Transactional
ですか?
回答:
@Transactional
トランザクションブロック内でメソッドを呼び出すと、親トランザクションは新しいメソッドに進みます。親メソッド(with @Transactional
)からの同じ接続と、呼び出されたメソッドで発生した例外(なし)@Transactional
は、トランザクション定義で構成されているようにトランザクションをロールバックします。
同じインスタンス内の@Transactional
メソッドからアノテーション付きのメソッドを呼び出す場合@Transactional
、呼び出されたメソッドのトランザクション動作はトランザクションに影響を与えません。ただし、トランザクション定義を持つ別のメソッドからトランザクション定義を持つメソッドを呼び出し、それらが異なるインスタンスにある場合、呼び出されるメソッドのコードは、呼び出されるメソッドで指定されたトランザクション定義に従います。
詳細については、Springトランザクションドキュメントの宣言型トランザクション管理のセクションを参照してください。
Spring宣言型トランザクションモデルはAOPプロキシを使用します。したがって、AOPプロキシはトランザクションの作成を担当します。AOPプロキシは、インスタンス内のメソッドがインスタンスの外部から呼び出された場合にのみアクティブになります。
will follow the transaction definitions given in the called method
でした。ただし、呼び出しが同じオブジェクトインスタンスからのものである場合、トランザクションの保守を担当するaopプロキシを介して呼び出しが伝播されないため、効果はありません。
@Transactional
異なるオブジェクト/インスタンスから定義を使用してメソッドを呼び出すと、呼び出し元のメソッドの@Transactional
属性が異なっていても、呼び出されたメソッドはそれ自体のトランザクション定義に従います。
それは伝播レベルに依存します。可能なすべてのレベル値は次のとおりです。
たとえば、伝播レベルがNESTEDの場合、現在のトランザクションは「一時停止」され、新しいトランザクションが作成されます(注:ネストされたトランザクションの実際の作成は、特定のトランザクションマネージャーでのみ機能します)。
デフォルトの伝播レベル(「動作」と呼ばれるもの)はREQUIREDです。@Transactional
アノテーションが付いた「内部」メソッドが呼び出された場合(またはXMLを介して宣言的にトランザクションされた場合)、同じトランザクション内で実行されます。たとえば、「何も新しいものは作成されません」。
@Transactionalはトランザクション境界(開始/終了)をマークしますが、トランザクション自体はスレッドにバインドされます。トランザクションが開始されると、元のメソッドが返され、トランザクションがコミット/ロールバックされるまで、メソッド呼び出し全体に伝播されます。
@Transactionalアノテーションを持つ別のメソッドが呼び出された場合、伝播はそのアノテーションの伝播属性に依存します。
内部メソッドに@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がスローされるため、トランザクションはロールバックに設定されますが、外部トランザクションには影響しません。外側のトランザクションは、内側のトランザクションが開始されると一時停止され、内側のトランザクションが終了すると再開されます。これらは互いに独立して実行されるため、外部トランザクションは正常にコミットされる場合があります。