アーキテクチャ
概観
Hibernateアーキテクチャの(非常に)高いレベルからのビュー:
この図はHibernateが、アプリケーションに対して永続化サービス
(と永続オブジェクト)を提供するために、データベースと設定データを使うことを
示しています。
ここで実行時アーキテクチャのより詳細なビューをお見せしましょう。
あいにく、Hibernateは柔軟であり、いろいろなアプローチをサポートしています。
ここでは、2つの極端な例をお見せします。
「軽い」アーキテクチャでは、アプリケーションが自前のJDBCコネクションを用意し、
アプリケーション自身がトランザクションを管理します。
この方法は、Hibernate APIの最小限のサブセットを使います:
「重い」アーキテクチャは、アプリケーションから、その下に位置するJDBCやJTAのAPIを
取り払って抽象化し、その詳細の面倒をHibernateに見させます。
以下は、上の図に含まれるオブジェクトの定義です:
SessionFactory (org.hibernate.SessionFactory)
1つのデータベースに対するコンパイルされたマッピングの
スレッドセーフな(更新不能の)キャッシュ。
Session のファクトリであり、
ConnectionProvider のクライアント。
オプションとして、プロセスまたはクラスタレベルにおいて、
トランザクション間で再利用可能なデータの(二次)キャッシュを持ちます。
Session (org.hibernate.Session)
アプリケーションと永続ストアとの対話を表す、
シングルスレッドで短命のオブジェクト。
JDBCコネクションをラップします。
Transaction のファクトリです。
永続オブジェクトの必須の(一次)キャッシュを保持します。
このキャッシュはオブジェクトグラフをナビゲーションする時や、
識別子でオブジェクトを検索する時に使われます。
Persistent objects と Collections
永続化状態とビジネスメソッドを持つ、短命でシングルスレッドのオブジェクト。
これは通常のJavaBeans/POJOのこともありますが、特徴的なことは、
その時点での(ただ1つの) Session と関連していることです。
Session がクローズされるとすぐに、
それらは切り離されて他のアプリケーション層から自由に使うことができます。
(例えばデータ・トランスファ・オブジェクトとして、
プレゼンテーション層から、またはプレゼンテーション層へ直接使用できます。)
Transient と detached な objects と Collections
現時点では Session と関連していない、
永続クラスのインスタンス。
すでにアプリケーション側でインスタンス化されていて、まだ永続化されていないか、
クローズされた Session でインスタンス化されたかのどちらかです。
Transaction (org.hibernate.Transaction)
(オプション)原子性を持つ作業単位(Unit of Work)を指定するために、アプリケーションが使用する、
シングルスレッドで短命なオブジェクト。
下に位置するJDBC、JTA、CORBAトランザクションからアプリケーションを抽象化します。
Session は、時には
いくつかの Transaction をまたがるかもしれません。
しかし、下の層のAPIを使うにせよ、 Transaction を使うにせよ、
トランザクション境界を設定することは、決してオプションではありません!。
ConnectionProvider (org.hibernate.connection.ConnectionProvider)
(オプション)JDBCコネクション(とそのプール)のファクトリ。
下の層に位置する Datasource や
DriverManager からアプリケーションを抽象化します。
アプリケーションには公開されませんが、開発者が継承または実装することは可能です。
TransactionFactory (org.hibernate.TransactionFactory)
(オプション) Transaction インスタンスのファクトリ。
アプリケーションには公開されませんが、開発者が継承または実装することは可能です。
Extension Interfaces
Hibernateは、永続層の振る舞いをカスタマイズするために、
多くのオプション拡張インタフェースを用意しています。
詳細はAPIドキュメントを参照してください。
「軽い」アーキテクチャでは、アプリケーションは直接JTAやJDBCと対話するために、
Transaction や TransactionFactory や
ConnectionProvider をバイパスします。
インスタンスの状態
永続クラスのインスタンスは、次の3つの異なる状態のどれかになります。
それは、 永続コンテキスト によって決まります。
Hibernateの Session オブジェクトが、永続コンテキストになります。
transient
この状態のインスタンスは、現在もそして過去においても、
永続コンテキストに関連づいていません。また、永続ID(主キーの値)を
持っていません。
persistent
この状態のインスタンスは、その時点で永続コンテキストに関連づいています。
また、永続ID(主キーの値)を持ち、
たいていはデータベースに対応する行を持っているでしょう。
個々の永続コンテキストのなかでは、永続IDが
JavaのID(オブジェクトのメモリ上の位置)と同じであることを
Hibernateが 保証 します。
detached
この状態のインスタンスは、かつて永続コンテキストに関連づけられたが、
そのコンテキストがクローズされたか、あるいは、
他のプロセスにそのインスタンスがシリアライズされたかです。
このインスタンスは、永続IDを持ち、たいていはデータベースに
対応する行を持っているでしょう。分離インスタンスに対しては、
永続IDとJavaのIDとの関連は、Hibernateが保証しません。
JMXとの統合
JMXはJavaコンポーネント管理のJ2EE標準です。
JMX標準サービスを通して、Hibernateは管理されます。
ディストリビューションの中に org.hibernate.jmx.HibernateService という
MBean実装を用意しています。
JBoss アプリケーションサーバー上にHibernateをJMXサービスとしてデプロイする方法の例としては、
JBoss ユーザガイドを参照してください。 JBoss アプリケーションサーバーにおいて、
JMXを使ってデプロイすると、次のメリットが得られます。
セッション管理: Hibernateの Session のライフサイクルは、
自動的にJTAトランザクションのスコープに結びつけられます。これは、もはや手動で
Session をオープンしたり、クローズしたりする必要がないことを意味します。
これは、JBoss EJB インターセプタの仕事になります。
また、コードのどこでトランザクション境界を設定するかについて、
もはや悩む必要がありません(もちろん移植可能な永続層を書かかなくていいのならば、
オプションのHibernateの Transaction を使用してください。)
Session にアクセスするためには、 HibernateContext を
コールしてください。
HAR デプロイ: 通常、(EAR または SAR ファイルにある)JBoss サービス
デプロイメントディスクリプタを使って、Hibernate JMX サービスをデプロイします。
それは、Hibernateの SessionFactory の全ての一般的な設定オプションを
サポートします。しかし依然としてデプロイメントディスクリプタのなかにすべてのマッピングファイルの
名前を挙げる必要があります。
もし、オプションのHARデプロイメントを使うことを決めたなら、
JBossは自動的にHARファイルのなかの全てのマッピングファイルを検出します。
これらのオプションについての詳細な情報は、JBossアプリケーションサーバユーザガイドを
参考にしてください。
JMXサービスとして利用可能な他の機能に、Hibernate実行時統計情報があります。
を見てください。
JCA サポート
Hibernate は JCA コネクタとしても設定できます。詳細については、Webサイトを見てください。
Hibernate JCA サポートは、今のところ実験段階として考えられていることに注意してください。
コンテキスト上のセッション
Hibernate を使ったアプリケーションは、ほとんど、なんらかの形で"コンテキスト上の"セッションが必要になります。
「コンテキスト上のセッション」は、特定のコンテキストのスコープのなかで有効なセッションのことです。
しかし、通常アプリケーションごとにコンテキストを構成するものの定義は異なります。
しかも、異なる複数のコンテキストは、現時点に対して異なるスコープを定義します。
バージョン3.0より前の Hibernate では、自作の ThreadLocal ベースの「コンテキスト上のセッション」を
利用するか、 HibernateUtil のようなヘルパークラスを利用するか、
proxy/interception ベースの「コンテキスト上のセッション」を提供する
(Spring や Pico のような)サードパーティのフレームワークを利用するかのいずれかでした。
バージョン 3.0.1 から、Hibernate には SessionFactory.getCurrentSession() が
加わりました。 これは、 JTA トランザクションの使用を前提にしています。
JTA トランザクションは、現在のセッションのスコープとコンテキストの両方を定義します。
Hibernate チームは、次のことを主張します。
巨大なスタンドアロンの JTA TransactionManager 実装が成熟したら、
J2EE コンテナ上にデプロイされるかどうかにかかわらず、
ほとんどの(すべてとは言わないが)アプリケーションが、
JTA トランザクション管理を使用すべきであると。
この考えに基づくと、 JTA ベースの「コンテキスト上のセッション」を
使うしかないでしょう。
しかし、バージョン 3.1 からは、 SessionFactory.getCurrentSession() の後の処理が、
プラガブルになりました。
これを受けて、現在のセッションを定義するスコープとコンテキストのプラガビリティを可能にするために、
新しい拡張インタフェース ( org.hibernate.context.CurrentSessionContext ) と
新しい構成パラメータ ( hibernate.current_session_context_class ) が追加されました。
org.hibernate.context.CurrentSessionContext インタフェースの規約についての
詳細な内容は Javadoc を参照してください。
それには、 currentSession() という1つのメソッドが定義されており、
その実装は、現在の「コンテキスト上のセッション」を追跡することに責任を持ちます。
そのまま使えるように、Hibernateはこのインタフェースの実装を2つ提供しています。
org.hibernate.context.JTASessionContext -
JTA トランザクションによって、現在のセッションが追跡され、
スコープを決められます。この処理は、古いJTAだけのアプローチとまったく同じです。
詳細はJavadocを参照してください。
org.hibernate.context.ThreadLocalSessionContext -
スレッドの実行によって、現在のセッションが追跡されます。
詳細はJavadocを参照してください。
org.hibernate.context.ManagedSessionContext -
スレッドの実行によって、現在のセッションが追跡されます。
しかし、このクラスのstaticメソッドで Session インスタンスを
バインド/アンバインドする責任はあなたにあります。
これは決して Session をオープン、フラッシュ、クローズしません。
始めの2つの実装は、"1セッション - 1データベーストランザクション" プログラミングモデルを提供します。
これは リクエストごとのセッション(session-per-request) としても知られており、使われています。
Hibernate セッションの開始と終了は、データベーストランザクションの期間で決まります。
JTAを使わない普通のJSEで、プログラム上のトランザクション境界設定を行うなら、
コードから基礎のトランザクションシステムを隠蔽するために、
Hibernate Transaction APIを使うとよいでしょう。
JTAを使うなら、トランザクションの境界設定には、JTAインターフェイスを使ってください。
CMTをサポートするEJBコンテナで実行するつもりなら、トランザクション境界は宣言的に定義できるため、
コード上でトランザクションやセッションの境界を設定する必要はありません。
さらに詳細な情報やコードの例は、 を参照してください。
hibernate.current_session_context_class 設定パラメータは、
org.hibernate.context.CurrentSessionContext のどの実装を使うかを指定します。
下位互換性のため、このパラメータが設定されず
org.hibernate.transaction.TransactionManagerLookup が設定されていた場合、
Hibernateは org.hibernate.context.JTASessionContext を使うことに注意してください。
通常このパラメータの値には、3つの実装の中から使用する実装クラスの名前を直接指定します。
しかし、"jta", "thread", "managed"というそれぞれの省略名も用意されています。