Hibernate.orgCommunity Documentation

第27章 ベストプラクティス

クラスは細かい粒度で書き <component> でマッピングしましょう。

street (通り)、 suburb (都市)、 state (州)、 postcode (郵便番号)をカプセル化する Address (住所)クラスを使いましょう。そうすればコードが再利用しやすくなり、リファクタリングも簡単になります。

永続クラスには識別子プロパティを定義しましょう。

Hibernate では識別子プロパティはオプションですが、使用すべき理由がたくさんあります。識別子は「人工的」(生成された、業務的な意味を持たない)なものにすることをおすすめします。

自然キーを見つけましょう。

すべてのエンティティに対して自然キーを見つけて、 <natural-id> でマッピングしましょう。自然キーを構成するプロパティを比較するために、 equals()hashCode() を実装しましょう。

クラスのマッピングはそれぞれのクラス専用のファイルに書きましょう。

単一の巨大なマッピングドキュメントを使用しないでください。 com.eg.Foo クラスなら com/eg/Foo.hbm.xml ファイルにマッピングしましょう。このことは、特にチームでの開発に意味があります。

リソースとしてマッピングをロードしましょう。

マッピングを、それらがマッピングするクラスと一緒に配置しましょう。

クエリ文字列を外部に置くことを考えましょう

クエリが ANSI 標準でない SQL 関数を呼んでいるなら、これはよいプラクティスです。クエリ文字列をマッピングファイルへ外出しすればアプリケーションがポータブルになります。

バインド変数を使いましょう。

JDBC の場合と同じように、定数でない値は必ず "?" で置き換えましょう。定数でない値をバインドするために、クエリで文字列操作を使ってはいけません。名前付きのパラメータを使うようにするとさらに良いです。

JDBC コネクションを管理してはいけません。

Hibernate ではアプリケーションが JDBC コネクションを管理することが許されています。しかしこれは最終手段だと思ってください。組み込みのコネクションプロバイダを使うことができなければ、 org.hibernate.connection.ConnectionProvider を実装することを考えてください。

カスタム型の使用を考えましょう。

あるライブラリから持ってきた Java 型を永続化する必要があるとしましょう。しかしその型には、コンポーネントとしてマッピングするために必要なアクセサがないとします。このような場合は org.hibernate.UserType の実装を考えるべきです。そうすれば Hibernate 型との実装変換を心配せずにアプリケーションのコードを扱えます。

ボトルネックを解消するには JDBC をハンドコードしましょう。

In performance-critical areas of the system, some kinds of operations might benefit from direct JDBC. Do not assume, however, that JDBC is necessarily faster. Please wait until you know something is a bottleneck. If you need to use direct JDBC, you can open a Hibernate Session, wrap your JDBC operation as a org.hibernate.jdbc.Work object and using that JDBC connection. This way you can still use the same transaction strategy and underlying connection provider.

Session のフラッシュを理解しましょう。

Session が永続状態をデータベースと同期させることがときどきあります。しかしこれがあまりに頻繁に起こるようだと、パフォーマンスに影響が出てきます。自動フラッシュを無効にしたり、特定のトランザクションのクエリや操作の順番を変更することで、不必要なフラッシュを最小限にできます。

3層アーキテクチャでは分離オブジェクトの使用を考えましょう。

サーブレット / セッション Bean アーキテクチャを使うとき、サーブレット層 / JSP 層間でセッション Bean でロードした永続オブジェクトをやり取りできます。その際リクエストごとに新しい Session を使ってください。また Session.merge()Session.saveOrUpdate() を使って、オブジェクトとデータベースを同期させてください。

2層アーキテクチャでは長い永続コンテキストの使用を考えましょう。

最高のスケーラビリティを得るには、データベーストランザクションをできるだけ短くしなければなりません。しかし長い間実行する アプリケーショントランザクション の実装が必要なことはしばしばです。これはユーザーの視点からは1個の作業単位(unit of work)になります。アプリケーショントランザクションはいくつかのクライアントのリクエスト/レスポンスサイクルにまたがります。アプリケーショントランザクションの実装に分離オブジェクトを使うのは一般的です。そうでなければ、2層アーキテクチャの場合は特に適切なことですが、アプリケーショントランザクションのライフサイクル全体に対して単一のオープンな永続化コンテキスト(セッション)を維持してください。そして単純にリクエストの最後に JDBC コネクションから切断し、次のリクエストの最初に再接続します。決して複数のアプリケーショントランザクションユースケースに渡って1個の Session を使い回さないでください。そうでなければ、古いデータで作業することになります。

例外を復帰可能なものとして扱ってはいけません。

これは「ベスト」プラクティス以上の、必須のプラクティスです。例外が発生したときは Transaction をロールバックして、 Session をクローズしてください。そうしないと Hibernate はメモリの状態が永続状態を正確に表現していることを保証できません。この特別な場合として、与えられた識別子を持つインスタンスがデータベースに存在するかどうかを判定するために、 Session.load() を使うことはやめてください。その代わりに Session.get() かクエリを使ってください。

関連にはなるべく遅延フェッチを使いましょう。

即時フェッチは控えめにしましょう。二次キャッシュには完全に保持されないようなクラスの関連には、プロキシと遅延コレクションを使ってください。キャッシュされるクラスの関連、つまりキャッシュがヒットする可能性が非常に高い関連は、 lazy="false" で積極的なフェッチを明示的に無効にしてください。結合フェッチが適切な特定のユースケースには、クエリで left join fetch を使ってください。

フェッチされていないデータに関わる問題を避けるために、 ビューの中でオープンセッションを使う (open session in view) パターンか、統制された 組み立てフェーズ (assembly phase) を使いましょう。

Hibernate は Data Transfer Objects (DTO) を書く退屈な作業から開発者を解放します。伝統的な EJB アーキテクチャでは DTO は2つ目的があります: 1つ目は、エンティティ Bean がシリアライズされない問題への対策です。2つ目は、プレゼンテーション層に制御が戻る前に、ビューに使われるすべてのデータがフェッチされて、 DTO に復元されるような組み立てフェーズを暗黙的に定義します。 Hibernate では1つ目の目的が不要になります。しかしビューのレンダリング処理の間、永続コンテキスト(セッション)をオープンにしたままにしなければ、組み立てフェーズはまだ必要です(分離オブジェクトの中のどのデータが利用可能かについて、プレゼンテーション層と厳密な取り決めをしているビジネスメソッドを考えてみてください)。これは Hibernate 側の問題ではありません。トランザクション内で安全にデータアクセスするための基本的な要件です。

Hibernate からビジネスロジックを抽象化することを考えましょう。

インターフェースで(Hibernate の)データアクセスコードを隠蔽しましょう。 DAOThread Local Session パターンを組み合わせましょう。 UserType で Hibernate に関連付けると、ハンドコードした JDBC で永続化するクラスを持つこともできます。(このアドバイスは「十分大きな」アプリケーションに対してのものです。テーブルが5個しかないようなアプリケーションには当てはまりません。)

珍しい関連マッピングは使わないようにしましょう。

よいユースケースに本当の多対多関連があることは稀です。ほとんどの場合「リンクテーブル」の付加的な情報が必要になります。この場合、リンククラスに2つの一対多関連を使う方がずっとよいです。実際ほとんどの場合、関連は一対多と多対一なので、他のスタイルの関連を使うときは本当に必要かどうかを考えてみてください。

なるべく双方向関連にしましょう。

単方向関連は双方向に比べて検索が難しくなります。大きなアプリケーションでは、ほとんどすべての関連が双方向にナビゲーションできなければなりません。