SpringとHibernateを使用してWebアプリケーションとバッチジョブの両方のトランザクションをセットアップする方法
-
28-09-2019 - |
質問
Spring 2.5とHibernate 3を使用するアプリケーションがあります。
プレゼンテーションレイヤー、サービスレイヤー、DAOレイヤーを備えたWebアプリケーション、および同じサービスとDAOレイヤーを共有するいくつかのクォーツジョブがあります。
トランザクションは、このような@Transactionalアノテーションを使用して、異なるレイヤーで初期化されます。
それは私がここで説明した問題に導いた: Spring 2.5での外部トランザクションからの内部トランザクション設定の制御
スプリングと冬眠をワイヤー化するためのトランザクションをセットアップする方法について少し読みました。推奨されるアプローチは、サービスレイヤーのトランザクションを初期化することです。
私が気に入らないのは、ほとんどのトランザクションが冬眠が適切に機能する必要があるという理由だけで存在するということです。
そして、複数のサービスメソッドを呼び出すジョブのトランザクションが本当に必要な場合、ジョブからのトランザクションを初期化することを選択することはできないようです。したがって、DAOからサービスに@Transactionalアノテーションを移動すると、違いが生じないようです。
この種のアプリケーションのためにトランザクションをセットアップすることをどのようにお勧めしますか?
解決
スプリングと冬眠をワイヤー化するためのトランザクションをセットアップする方法について少し読みました。推奨されるアプローチは、サービスレイヤーのトランザクションを初期化することです。
絶対。トランザクション境界は、DAOレイヤーレベルではなく、サービスレイヤーレベルで行う必要があります。
- 仕事のユニットはサービスであり、DAOではなく
- 必要に応じて、トランザクションを複数のDAOに渡す必要があります。
私が気に入らないのは、ほとんどのトランザクションが冬眠が適切に機能する必要があるという理由だけで存在するということです。
トランザクションは冬眠に固有ではないため、この部分を詳しく説明する必要があります。
そして、複数のサービスメソッドを呼び出すジョブのトランザクションが本当に必要な場合、ジョブからのトランザクションを初期化することを選択することはできないようです。
ジョブレイヤーから開始されたトランザクション内で複数のサービスを呼び出す場合は、サービスを取引と宣言します REQUIRED
セマンティクス(デフォルト)およびSpring Transactionの伝播に依存します(これは、リモートコールが必要な場合に適用されます。その場合、EJBを使用します)。
したがって、DAOからサービスに@Transactionalアノテーションを移動すると、違いが生じないようです。
これ します 違いを生み出し、バッチを実行するときにジョブレイヤーからトランザクションを開始する必要があるという事実は、物事が違うものではありません。
私は暖かく読むことをお勧めします 第9章トランザクション管理.
(...)私の主な問題は冬眠から来ています。私がはっきりしていなかったらごめんなさい。
問題ない。質問があいまいになったとき、あなたはしばしばあいまいな答えを得るということです:)
Hibernateのドキュメントから:「データベーストランザクションは決してオプションではありません。データベースとのすべての通信は、トランザクション内で発生する必要があります。」そのため、開発者は私のプロジェクトにDAO Methods Transactionalを配置しました。
申し訳ありませんが、上記の声明はそれだけを言っています 「データベースとの通信が発生する必要があります 中身 トランザクション」, 、それ以上のことは何もありません。また、どこから取引を開始するかを決定することは、あなたの裁量(通常はサービスレイヤー)に残されています。あなたがDAOレベルでそれをするなら、もし MySuperService
電話 DaoFoo
と DaoBar
と DaoBar
失敗しますか?そのような場合、あなたはおそらくすべての変更をロールバックしたいと思うでしょう。 DaoBar
. 。したがって、作業単位が始まる場所でトランザクションを制御する必要性。
私見、開発者はいくつかのガイダンスを必要としています。
それは私のすべてのサービスがトランザクションであるべきだということですか?たとえば、データを読んだときでも?
まず、読むことをお勧めします 非輸送データアクセスと自動コミットモード (の弟 セッションとトランザクション)物事を明確にする 「読み取り専用のトランザクション」. 。ページ全体を読む価値はありますが、この特定の部分を引用してみましょう。
多くのアプリケーション開発者は、トランザクション以外のデータベースと話すことができると考えています。これは明らかに不可能です。 データベーストランザクション以外のデータベースにSQLステートメントを送信することはできません. 。非換算データアクセスという用語は、明示的なトランザクション境界、システムトランザクションがなく、データアクセスの動作がオートコンミットモードの動作であることを意味します。物理データベーストランザクションが関係しないという意味ではありません。
上記のリンクが完了したら、次の提案された読書は @transactional読み取り専用フラグの落とし穴. 。これが関連する部分です:
(...)一番下の行では、ORMベースのフレームワークを使用する場合、読み取り専用フラグは非常に役に立たず、ほとんどの場合無視されます。ただし、まだリスト9に示すように、常に伝播モードをサポートに設定しているため、トランザクションは開始されません。
リスト9.読み取り専用と
SUPPORTS
選択操作の伝播モード@Transactional(readOnly = true, propagation=Propagation.SUPPORTS) public TradeData getTrade(long tradeId) throws Exception { return em.find(TradeData.class, tradeId); }
さらに良いことに、使用しないでください
@Transactional
リスト10に示すように、読み取り操作を行うときに全く注釈リスト10.削除
@Transactional
選択操作の注釈public TradeData getTrade(long tradeId) throws Exception { return em.find(TradeData.class, tradeId); }