Spring -@Transactional-バックグラウンドで何が起こりますか?
-
11-09-2019 - |
質問
メソッドに注釈を付けたときに実際に何が起こるか知りたい @Transactional
?もちろん、Springがその方法をトランザクションで包むことを知っています。
しかし、私には次の疑問があります:
- 春が作成すると聞いた プロキシクラス?誰かがこれをもっと説明できますか 深さ. そのプロキシクラスに実際に存在するものは何ですか?実際のクラスはどうなりますか?スプリングの作成されたプロキシクラスをどのように見ることができますか
- 春のドキュメントでも読みました。
注:このメカニズムはプロキシに基づいているため、 プロキシを介して入る「外部」メソッド呼び出しのみが傍受されます. 。これは、「自己負担」、つまりターゲットオブジェクトの他のメソッドを呼び出すターゲットオブジェクト内のメソッドが、呼び出されたメソッドがでマークされている場合でも、実行時に実際のトランザクションにつながらないことを意味します。
@Transactional
!
ソース: http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html
なぜ外部メソッド呼び出しのみがトランザクションの下にあり、自己負担方法ではないのですか?
解決
これは大きなトピックです。 Spring Reference Docは、複数の章を捧げます。読むことをお勧めします アスペクト指向プログラミング と トランザクション, 、Springの宣言的トランザクションサポートは、その基礎でAOPを使用しています。
しかし、非常に高いレベルで、春は宣言するクラスのプロキシを作成します @transactional クラス自体またはメンバーについて。プロキシは、実行時にほとんど見えません。これは、スプリングがプロキシ化されるオブジェクトへのメソッド呼び出しの前、後、後、またはその周りに動作を注入する方法を提供します。トランザクション管理は、接続できる動作の一例にすぎません。セキュリティチェックは別です。また、ロギングなどのために独自のものを提供することもできます。したがって、メソッドに注釈を付けたとき @transactional, 、スプリングは、注釈を付けているクラスと同じインターフェイスを実装するプロキシを動的に作成します。また、クライアントがオブジェクトに呼び出しを行うと、呼び出しが傍受され、動作がプロキシメカニズムを介して注入されます。
ちなみに、EJBのトランザクションも同様に機能します。
あなたが観察したように、介して、プロキシメカニズムは、呼び出しが何らかの外部オブジェクトから送信されたときにのみ機能します。オブジェクト内で内部呼び出しを行うとき、あなたは本当に「」を通して電話をかけますこれ「参照、プロキシをバイパスします。その問題を回避する方法があります。私は1つのアプローチを説明します。 このフォーラム投稿 私はaを使用します BeanFactoryPostProcessor 実行時にプロキシのインスタンスを「自己参照」クラスに挿入する。この参照を「」と呼ばれるメンバー変数に保存します自分「。スレッドのトランザクションステータスの変更を必要とする内部呼び出しを行う必要がある場合は、プロキシを介して通話を指示します(例えば」me.somemethod()"。)フォーラムの投稿では、より詳細に説明しています。 BeanFactoryPostProcessor コードは、春1.xの時間枠に書き戻されたため、今は少し異なります。しかし、うまくいけば、それはあなたにアイデアを与えます。おそらく利用できるようにすることができる更新されたバージョンがあります。
他のヒント
SpringがBeanの定義をロードし、@TransactionAl Annotationsを探すように構成されている場合、実際のBeanの周りにこれらのプロキシオブジェクトを作成します。これらのプロキシオブジェクトは、実行時に自動生成されるクラスのインスタンスです。メソッドが呼び出されたときのこれらのプロキシオブジェクトのデフォルトの動作は、「ターゲット」ビーン(つまり、豆)に同じメソッドを呼び出すことです。
ただし、プロキシはインターセプターで提供することもでき、存在すると、これらのインターセプターは、ターゲットビーンの方法を呼び出す前にプロキシによって呼び出されます。 @Transactionalで注釈を付けたターゲットビーンの場合、SpringはTransactionInterceptorを作成し、生成されたプロキシオブジェクトに渡します。そのため、クライアントコードからメソッドを呼び出すと、最初にトランザクションインターセプター(トランザクションを開始)を呼び出すプロキシオブジェクトのメソッドを呼び出します。これは、ターゲットビーンのメソッドを呼び出します。呼び出しが終了すると、TransactionInterceptorはトランザクションをコミット/ロールバックします。クライアントコードに対して透明です。
「外部方法」については、Beanが独自の方法の1つを呼び出した場合、プロキシを介してそうすることはありません。スプリングはあなたの豆をプロキシで包むことを忘れないでください、あなたの豆にはそれについての知識がありません。 「外部」からの呼び出しのみがあなたの豆がプロキシを通過します。
それは助けますか?
視覚的な人として、私はプロキシパターンのシーケンス図で重量を量るのが好きです。矢印の読み方がわからない場合は、このような最初のものを読みます。 Client
実行します Proxy.method()
.
- クライアントは自分の視点からターゲットのメソッドを呼び出し、プロキシによって静かに傍受されます
- 前のアスペクトが定義されている場合、プロキシはそれを実行します
- 次に、実際のメソッド(ターゲット)が実行されます
- 後退と投球後の投げは、メソッドが返された後に実行されるオプションの側面、および/またはメソッドが例外をスローする場合
- その後、プロキシは後のアスペクトを実行します(定義されている場合)
- 最後に、プロキシは呼び出しクライアントに戻ります
(私はその起源に言及したことを条件に写真を投稿することを許可されました。著者:ノエル・ヴァース、ウェブサイト:www.noelvaes.eu)
最も簡単な答えは、 どの方法で@Transactionalを宣言しても、メソッドが完了したときにトランザクションの境界が開始され、境界が終了します。
JPAコールを使用している場合、すべてのコミットがこのトランザクション境界にあります。 Entity1、Entity2、およびEntity3を保存しているとしましょう。 Entity3を保存する間、Enitiy1とEntity2が同じトランザクションで行われるため、Entity1とEntity2はEntity3でロールバックされます。
トランザクション:( entity1.save、entity2.save、entity3.save)。どんな例外でも、DBを使用したすべてのJPAトランザクションのロールバックが発生します。 内部的にJPAトランザクションは春までに使用されます。