1
<?xml version="1.0" encoding="UTF-8"?>
2
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
4
<chapter id="best-practices" revision="3">
5
<title>ベストプラクティス</title>
7
<variablelist spacing="compact">
10
クラスは細かい粒度で書き <literal><component></literal> でマッピングしましょう。</term>
13
<literal>street</literal>(通り), <literal>suburb</literal>
14
(都市), <literal>state</literal>(州), <literal>postcode</literal>
15
(郵便番号)をカプセル化する <literal>Address</literal>(住所)クラスを使いましょう。
16
そうすればコードが再利用しやすくなり、リファクタリングも簡単になります。
22
永続クラスには識別子プロパティを定義しましょう。</term>
25
Hibernateでは識別子プロパティはオプションですが、
27
識別子は「人工的」(生成された、業務的な意味を持たない)
33
<term>自然キーを見つけましょう。</term>
36
すべてのエンティティに対して自然キーを見つけて、
37
<literal><natural-id></literal> でマッピングしましょう。
38
自然キーを構成するプロパティを比較するために、
39
<literal>equals()</literal> と <literal>hashCode()</literal> を実装しましょう。
44
<term>クラスのマッピングはそれぞれのクラス専用のファイルに書きましょう。</term>
47
単一の巨大なマッピングドキュメントを使用しないでください。
48
<literal>com.eg.Foo</literal> クラスなら
49
<literal>com/eg/Foo.hbm.xml</literal> ファイルにマッピングしましょう。
50
このことは、特にチームでの開発に意味があります。
55
<term>リソースとしてマッピングをロードしましょう。</term>
58
マッピングを、それらがマッピングするするクラスと一緒に配置しましょう。
63
<term>クエリ文字列を外部に置くことを考えましょう</term>
66
クエリがANSI標準でないSQL関数を呼んでいるなら、これはよいプラクティスです。
67
クエリ文字列をマッピングファイルへ外出しすればアプリケーションがポータブルになります。
72
<term>バインド変数を使いましょう。</term>
75
JDBCの場合と同じように、定数でない値は必ず"?"で置き換えましょう。
76
定数でない値をバインドするために、クエリで文字列操作を使ってはいけません。
77
名前付きのパラメータを使うようにするとさらに良いです。
82
<term>JDBCコネクションを管理してはいけません。</term>
85
HibernateではアプリケーションがJDBCコネクションを管理することが許されています。
87
組み込みのコネクションプロバイダを使うことができなければ、
88
<literal>org.hibernate.connection.ConnectionProvider</literal> を実装することを考えてください。
93
<term>カスタム型の使用を考えましょう。</term>
96
あるライブラリから持ってきたJava型を永続化する必要があるとしましょう。
97
しかしその型には、コンポーネントとしてマッピングするために必要なアクセサがないとします。
98
このような場合は <literal>org.hibernate.UserType</literal> の実装を考えるべきです。
99
そうすればHibernate型との実装変換を心配せずにアプリケーションのコードを扱えます。
104
<term>ボトルネックを解消するにはJDBCをハンドコードしましょう。</term>
107
システムのパフォーマンスクリティカルな領域では、
108
ある種の操作にJDBCを直接使うと良いかもしれません。
109
しかし何がボトルネックになっているか <emphasis>はっきりする</emphasis> までは待ってください。
110
またJDBCを直接使うからといって、必ずしも速くなるとは限らないことも理解してください。
111
JDBCを直接使う必要があれば、Hibernateの <literal>Session</literal> をオープンして、
112
JDBCコネクションを使うと良いかもしれません。
113
依然として同じトランザクション戦略とコネクションプロバイダが使えるからです。
118
<term><literal>Session</literal> のフラッシュを理解しましょう。</term>
121
Sessionが永続状態をデータベースと同期させることがときどきあります。
122
しかしこれがあまりに頻繁に起こるようだと、パフォーマンスに影響が出てきます。
123
自動フラッシュを無効にしたり、特定のトランザクションのクエリや操作の順番を変更することで、
129
<term>3層アーキテクチャでは分離オブジェクトの使用を考えましょう。</term>
132
サーブレット / セッションビーンアーキテクチャを使うとき、
133
サーブレット層 / JSP層間でセッションビーンでロードした永続オブジェクトをやり取りできます。
134
その際リクエストごとに新しいSessionを使ってください。
135
また <literal>Session.merge()</literal> や <literal>Session.saveOrUpdate()</literal>
136
を使って、オブジェクトとデータベースを同期させてください。
141
<term>2層アーキテクチャでは長い永続コンテキストの使用を考えましょう。</term>
145
データベーストランザクションをできるだけ短くしなければなりません。
146
しかし長い間実行する <emphasis>アプリケーショントランザクション</emphasis>
148
これはユーザの視点からは1個の作業単位(unit of work)になります。
149
アプリケーショントランザクションはいくつかのクライアントのリクエスト/レスポンスサイクルにまたがります。
150
アプリケーショントランザクションの実装に分離オブジェクトを使うのは一般的です。
152
そうでなければ、2層アーキテクチャの場合は特に適切なことですが、
153
アプリケーショントランザクションのライフサイクル全体に対して
154
単一のオープンな永続化コンテキスト(セッション)を維持してください。
155
そして単純にリクエストの最後にJDBCコネクションから切断し、
158
決して複数のアプリケーショントランザクションユースケースに渡って
159
1個のSessionを使い回さないでください。
160
そうでなければ、古いデータで作業することになります。
165
<term>例外を復帰可能なものとして扱ってはいけません。</term>
168
これは「ベスト」プラクティス以上の、必須のプラクティスです。
169
例外が発生したときは <literal>Transaction</literal> をロールバックして、
170
<literal>Session</literal> をクローズしてください。
171
そうしないとHibernateはメモリの状態が永続状態を正確に表現していることを保証できません。
172
この特別な場合として、与えられた識別子を持つインスタンスがデータベースに存在するかどうかを判定するために、
173
<literal>Session.load()</literal> を使うことはやめてください。
174
その代わりに <literal>Session.get()</literal> かクエリを使ってください。
179
<term>関連にはなるべく遅延フェッチを使いましょう。</term>
183
二次キャッシュには完全に保持されないようなクラスの関連には、
184
プロキシと遅延コレクションを使ってください。
185
キャッシュされるクラスの関連、つまりキャッシュがヒットする可能性が非常に高い関連は、
186
<literal>lazy="false"</literal> で積極的なフェッチを明示的に無効にしてください。
187
結合フェッチが適切な特定のユースケースには、
188
クエリで <literal>left join fetch</literal> を使ってください。
194
フェッチされていないデータに関わる問題を避けるために、
195
<emphasis>ビューの中でオープンセッションを使う(open session in view)</emphasis>
196
パターンか、統制された <emphasis>組み立てフェーズ(assembly phase)</emphasis> を使いましょう。
200
Hibernateは <emphasis>Data Transfer Objects</emphasis> (DTO)を書く退屈な作業から開発者を解放します。
201
伝統的なEJBアーキテクチャではDTOは二つ目的があります:
202
1つ目は、エンティティビーンがシリアライズされない問題への対策です。
203
2つ目は、プレゼンテーション層に制御が戻る前に、
204
ビューに使われるすべてのデータがフェッチされて、DTOに復元されるような組み立てフェーズを暗黙的に定義します。
205
Hibernateでは1つ目の目的が不要になります。
206
しかしビューのレンダリング処理の間、永続コンテキスト(セッション)をオープンにしたままにしなければ、
207
組み立てフェーズはまだ必要です(分離オブジェクトの中のどのデータが利用可能かについて、
208
プレゼンテーション層と厳密な取り決めをしているビジネスメソッドを考えてみてください)。
209
これはHibernate側の問題ではありません。
210
トランザクション内で安全にデータアクセスするための基本的な要件です。
215
<term>Hibernateからビジネスロジックを抽象化することを考えましょう。</term>
218
インターフェイスで(Hibernateの)データアクセスコードを隠蔽しましょう。
219
<emphasis>DAO</emphasis> と <emphasis>Thread Local Session</emphasis> パターンを組み合わせましょう。
220
<literal>UserType</literal> でHibernateに関連付けると、
221
ハンドコードしたJDBCで永続化するクラスを持つこともできます。
222
(このアドバイスは「十分大きな」アプリケーションに対してのものです。
223
テーブルが5個しかないようなアプリケーションには当てはまりません。)
228
<term>珍しい関連マッピングは使わないようにしましょう。</term>
231
よいユースケースに本当の多対多関連があることは稀(まれ)です。
232
ほとんどの場合「リンクテーブル」の付加的な情報が必要になります。
233
この場合、リンククラスに2つの1対多関連を使う方がずっと良いです。
234
実際ほとんどの場合関連は1対多と多対1なので、
235
他のスタイルの関連を使うときは本当に必要かどうかを考えてみてください。
240
<term>なるべく双方向関連にしましょう。</term>
243
単方向関連は双方向に比べて検索が難しくなります。
245
ほとんどすべての関連が双方向にナビゲーションできなければなりません。