11.2. データベーストランザクション境界
データベース もしくはシステム:トランザクションの境界は、常に必要です。データベーストランザクションの外で、データベースとの通信は起きません(これは自動コミットモードに慣れている多くの開発者を混乱させるかもしれません)。読み込むだけの操作にでも、いつも明確なトランザクション境界を使用してください。分離レベルとデータベースの能力次第で、これは必要ないかもしれませんが、常にトランザクション境界を明示的に指定しても、マイナス面は全くありません。確かに、1つのデータベーストランザクションは多数の小さなトランザクションより 、データの読み込みであっても パフォーマンスがすぐれています。
J2EE 環境に管理されていない状態 (すなわち、スタンドアロン、単純な Web や Swing アプリケーション)でも、管理された状態でも、Hibernate アプリケーションを実行できます。管理されていない環境では、 Hiberante がデータベースのコネクションプールを提供します。アプリケーション開発者は、トランザクション境界を手動で設定しなければなりません。言い換えると、データベーストランザクションの開始、コミット、ロールバックを開発者自身が設定する必要があるということです。通常、管理された環境では、コンテナ管理によるトランザクション (CMT) が提供されます。(例えば、セッション Bean のデプロイメントディスクリプタで)宣言的に定義し、トランザクションを組み立てます。プログラムによるトランザクション境界はもう必要ありません。
しかしながら、管理されていないリソースローカルな環境と JTA に依存したシステム (CMT ではなく BMT) の両方に、永続化層を移植可能な状態に保つのは、通常望ましいことです。デプロイ環境のネイティブのトランザクションシステムへ変換する
Transaction というラッパー API を Hibernate が提供します。このAPIを使うかは実際任意ではありますが、CMT のセッション Beanでの操作がないのであれば、APIの使用を強く推奨します。
通常、
Session 終了には、4つの異なるフェーズがあります:
- セッションのフラッシュ
- トランザクションのコミット
- セッションのクローズ
- 例外のハンドリング
セッションのフラッシュについては、前述しましたので、管理された環境と管理されていない環境の両方について、トランザクション境界と例外ハンドリングをもっと詳しく見ていきましょう。
11.2.1. 管理されていない環境 リンクのコピーリンクがクリップボードにコピーされました!
リンクのコピーリンクがクリップボードにコピーされました!
Hibernate の永続化層を管理されていない環境で実装する場合は、通常単純なコネクションプール (すなわち非 DataSource) によって、データベースコネクションを処理します。Hibernate はそのコネクションプールから必要なコネクションを取得します。セッション/トランザクション処理のイディオムは次のようになります:
// Non-managed environment idiom
Session sess = factory.openSession();
Transaction tx = null;
try {
tx = sess.beginTransaction();
// do some work
...
tx.commit();
}
catch (RuntimeException e) {
if (tx != null) tx.rollback();
throw e; // or display error message
}
finally {
sess.close();
}
明示的に
Session の flush() を呼び出すべきではなく、そのセッションの 「セッションのフラッシュ」 によっては、commit() を呼び出すことにより、自動的に同期化処理が実行されます。 close() を呼び出すことにより、セッションの終わりを明確にします。 close() が暗黙的に行う主なことは、セッションが JDBC コネクションを開放することです。上記の Java コードはポータブルであり、管理されていない環境と JTA 環境の両方で実行できます。
すでに説明したように、はるかに適応性のある解決策は、Hibernate に予め組み込まれている 「current session」コンテキスト管理です。
// Non-managed environment idiom with getCurrentSession()
try {
factory.getCurrentSession().beginTransaction();
// do some work
...
factory.getCurrentSession().getTransaction().commit();
}
catch (RuntimeException e) {
factory.getCurrentSession().getTransaction().rollback();
throw e; // or display error message
}
正規のアプリケーションの中では、このようなコードの切れ端を決して見ないでしょう。致命的な (システム) 例外は、常に「最上位」でキャッチすべきです。言い換えれば、永続化層でHibernate 呼び出しを実行するコードと、
RuntimeException を処理する (通常はクリーンアップと終了のみ行うことができる) コードは、別々の層にあります。Hibernate による現在のコンテキスト管理は、SessionFactory にアクセスするだけでこの設計をかなり単純にします。例外処理は、この章の後のほうで議論します。
org.hibernate.transaction.JDBCTransactionFactory (デフォルト)を選択するべきです。第2の用例としては、"thread" をhibernate.current_session_context_class を選択するとよいでしょう。