リスト1●アプリケーションの共通情報を管理するcontext.xml(一部)
リスト1●アプリケーションの共通情報を管理するcontext.xml(一部)
[画像のクリックで拡大表示]
表2●context.xmlの<Resource>要素で指定できる主な属性
表2●context.xmlの<Resource>要素で指定できる主な属性
[画像のクリックで拡大表示]
リスト2●Hibernateによる接続情報を定義するhibernate.cfg.xml(一部)
リスト2●Hibernateによる接続情報を定義するhibernate.cfg.xml(一部)
[画像のクリックで拡大表示]
表3●hibernate.cfg.xmlの<property>要素で指定できる主な属性
表3●hibernate.cfg.xmlの<property>要素で指定できる主な属性
[画像のクリックで拡大表示]
表4●bookテーブルの構造
表4●bookテーブルの構造
[画像のクリックで拡大表示]
リスト3●マッピング・ファイルであるBOOK.hbm.xml(一部)
リスト3●マッピング・ファイルであるBOOK.hbm.xml(一部)
[画像のクリックで拡大表示]
リスト4●永続化クラスであるBook.java
リスト4●永続化クラスであるBook.java
[画像のクリックで拡大表示]
リスト5●bookテーブルにアクセスするサーブレットであるSelectServlet.java(一部)
リスト5●bookテーブルにアクセスするサーブレットであるSelectServlet.java(一部)
[画像のクリックで拡大表示]
図3●SelectServletの実行結果。サンプルではhttp://localhost:8080/nikkei200510/SelectServletにアクセスして起動する
図3●SelectServletの実行結果。サンプルではhttp://localhost:8080/nikkei200510/SelectServletにアクセスして起動する
[画像のクリックで拡大表示]
表5●Expressionクラスで利用できる主なメソッド
表5●Expressionクラスで利用できる主なメソッド
[画像のクリックで拡大表示]
リスト6●内部で実行されているSQL文
リスト6●内部で実行されているSQL文
[画像のクリックで拡大表示]
図4●書籍データの入力画面。サンプルではhttp://localhost:8080/nikkei200510/insert.jspにアクセスすると表示される
図4●書籍データの入力画面。サンプルではhttp://localhost:8080/nikkei200510/insert.jspにアクセスすると表示される
[画像のクリックで拡大表示]
リスト7●フォームからの入力値を処理するInsertServlet.java(一部)
リスト7●フォームからの入力値を処理するInsertServlet.java(一部)
[画像のクリックで拡大表示]
リスト8●データベースの更新/削除を行うUpdateServlet.java(一部)
リスト8●データベースの更新/削除を行うUpdateServlet.java(一部)
[画像のクリックで拡大表示]

ファイルの役割を理解すれば
設定は難しくない

 Hibernateを利用するには,あらかじめいくつかの設定ファイルを用意しておく必要があります。O/Rマッピングというと,関係する設定ファイルが多いせいか,「使い始めるまでが大変」というイメージがあるようです。しかし,それぞれのファイルの役割を理解していれば,難しい点はありません。

 最初にきちんと準備さえすれば,あとは設定ファイルを書き換えるだけで済むという手軽さが,O/Rマッピング導入のメリットです。設定ファイルを極めることは,O/Rマッピングを極めることでもあります。

(1)コネクション・プールを設定

 サーバーサイドの世界では,不特定多数のユーザーが間断なくデータベースにアクセスするのが普通です。このような状況で,毎回,データベースへの接続処理を行わなければならないとすれば,大変な負荷になります。恒常的に利用されることがあらかじめわかっているリソースは,あらかじめ確保しておくほうが無駄がなくなります。

 そこで登場するのが「コネクション・プーリング(Connection Pooling)」です。その名の通り,データベースへの接続をあらかじめいくつかプール(保持)しておく仕組みを指します。アプリケーションは,プーリングされた接続を必要に応じて取り出し,不要になったら,またプールに戻します。これにより,接続処理の負荷を軽減できます。サーバーサイド・アプリケーションにとって,コネクション・プーリングは必須といっていい技術です。

 Hibernateは,コネクション・プーリングの仕組みを標準で提供していますが,機能としては原始的であり,実運用では利用すべきではありません。たいていのアプリケーション・サーバー(コンテナ)は,コネクション・プーリングの仕組みを標準で装備しているので,こちらを優先して利用するようにしてください。

 コネクション・プーリングの設定方法は,使用しているコンテナによって異なります。今回はTomcat 5.5.x環境を前提に説明します。

 Tomcat 5.5.xでのコネクション・プールの設定は,アプリケーション・ルート配下の「/META-INF/context.xml」に記述します(リスト1[拡大表示])。context.xmlは,コンテキスト(アプリケーション)にかかわる共通情報を管理する設定ファイルです。コネクション・プーリングにかかわる設定は<Resource>要素に記述します。<Resource>要素で定義可能な属性は,表2[拡大表示]の通りです。ここに示していない属性は,たいてい固定値だと思って構いません。

 また,接続に利用するJDBCドライバを配置しておきます。コンテナのコネクション・プーリング機能を利用するので,コンテナから参照可能な「%CATALINA_HOME%/common/lib」にJDBCドライバを配置しなければならないことに注意してください。アプリケーション・ルート配下の「/WEB-INF/lib」フォルダに配置しても,コンテナはJDBCドライバを認識できません。

(2)Hibernateの基本定義ファイルを記述

 次に,Hibernateによる接続情報を定義するhibernate.cfg.xml(リスト2[拡大表示])を記述します。hibernate.cfg.xmlは,Hibernateが使用するデータソースを関連付けると同時に,Hibernateの挙動やマッピング・ファイル(後述)の位置を宣言するためのファイルです。hibernate.cfg.xmlには,クラス・パスが通っている必要があるので,アプリケーション・ルート配下の「/WEB-INF/classes」フォルダに配置するのが一般的です。

 一連の属性情報を設定するのは,<property>要素の役割です。<property>要素で指定可能な主な属性は表3[拡大表示]の通りです。<mapping>要素には,アプリケーションで利用するマッピング・ファイルのパスを指定します。

(3)マッピング・ファイルを定義

 マッピング・ファイルは,その名の通り,テーブル上のフィールドとJavaクラス配下のプロパティとを関連付けるファイルです。今回のサンプルからアクセスするbookテーブルは表4[拡大表示]のような構成になっています。

 マッピング・ファイルのファイル名は,hibernate.cfg.xml(リスト2[拡大表示])で指定したファイル名に対応したものになります。サンプルでは「BOOK.hbm.xml」です(リスト3[拡大表示])。マッピング・ファイルの<class>要素では,テーブル(table属性)とクラスの完全修飾名(name属性)とを関連付けます。

 配下の<id>要素では主キー,<property>要素ではそのほかのフィールドをそれぞれマッピングします。name,type,column属性は,それぞれ「プロパティ名」「データ型」「対応するテーブル上のフィールド名」を表します。<generator>要素では主キーを生成するジェネレータを指定します。assignedはアプリケーションが自前でキーを設定することを表します。

 hibernate.cfg.xmlと同様に,BOOK.hbm.xmlにもクラス・パスが通っている必要があります。「/WEB-INF/classes」フォルダに配置するのが一般的です。

(4)永続化クラスを用意

 次に,テーブルと関連付けるためのJavaのクラス(永続化クラス)を用意します(リスト4[拡大表示])。永続化クラスはフィールド値を保持するためのプライベート・フィールドとアクセサ・メソッドとを持つ単純なJavaBeansクラスです。永続化クラスは,以下の条件を満たしている必要があります。

  • デフォルト・コンストラクタ*2を持つ
  • プライベート・フィールドに対応するアクセサ・メソッドを持つ
  • 主キーを持つ場合には,これを保持するプライベート・フィールドと対応するアクセサ・メソッドを持つ

 これにより,テーブルから取り出した結果セットを永続化クラスにマッピングできるようになります。

データベースのテーブルから
データを抽出する

 以上で,Hibernateを利用するための準備は完了です。それでは,いよいよサーブレットからデータベース上のbookテーブルにアクセスしてみましょう。

 まず特定の条件に従って,データベースから結果セットを取り出してみます。bookテーブルにアクセスするサーブレットであるSelectServlet.javaをリスト5[拡大表示]に示しました。出版社(publishedフィールド)が「翔泳社」である書籍のデータを,ISBNコード(isbnフィールド)が降順になるように取り出しています。これらをHTMLのテーブルに整形して出力しています(図3[拡大表示])。

 接続セッションを管理するのはSessionオブジェクトの役割です。リスト5[拡大表示](1)の手順により,Hibernateは基本定義に基づいて接続セッションを確立します。

 次に,Criteriaオブジェクトで,テーブルからデータを条件抽出し,並べ替えます。Session#createCriteriaメソッドでCriteriaオブジェクトを生成した後,addメソッドで条件式の追加,addOrderメソッドでソート順の追加を行います。条件式を管理するExpressionオブジェクトで利用可能なメソッドを表5[拡大表示]にまとめました。サンプルでは,実際にはリスト6[拡大表示]に示したSQL文が内部で実行されています。hibernate.cfg.xmlでshow_sqlプロパティをtrueに設定している場合,内部的に生成されたSQL文は「%CATALINA_HOME%/logs/stdout.log」で確認できます。

 データベースから取り出した結果セットの内容は,Criteria#listメソッドで取得できます。listメソッドは,結果セットを永続化クラスであるBookにマッピングした結果を,Bookクラスのリスト(Listオブジェクト)として返します。ここでは,Listオブジェクトの内容をリクエスト属性"books"にセットし,表示用のJSP(JavaServer Pages)ページであるselect.jspに転送しています。

 select.jspではListオブジェクトの内容をHTMLのテーブルに整形する処理を行っています(リストの掲載は省略しました)。データベースへのアクセスが終わったら,Session#closeメソッドでセッションをクローズしておきます。

フォームの入力値を
データベースに登録

 次に,HTMLフォームに入力した情報をデータベースに登録してみましょう(図4[拡大表示])。フォームからの入力値を処理するのは,InsertServlet(リスト7[拡大表示])の役割です。文字化けを防ぐため,入力データの文字エンコーディングを必ず宣言します(リスト7[拡大表示](1))。

 登録/更新命令を実行する際には,トランザクションを利用します。トランザクションを開始するのは,Session#beginTransactionメソッドの役割です。

 データを登録するのは簡単です。永続化クラスBookの新しいインスタンスを生成し,setterメソッド経由で入力値を設定するだけです。あとはSession#saveメソッドで永続化クラスの内容をデータベースに反映します。トランザクションを利用している場合には,Transaction#commitメソッドで反映内容をコミットするのを忘れないでください。

 データベースの更新/削除も,ほとんど同じ要領でできます(リスト8[拡大表示])。Session#loadメソッドで第2引数に抽出キーを指定し,永続化クラスをインスタンス化します。あとは変更するフィールドをsetterメソッドで設定し,Session#updateメソッドで更新処理を行うだけです。データを削除する場合は,deleteメソッドを使用してください。

☆     ☆     ☆

 今回は,O/Rマッピング・ツールを利用して,簡単なデータ登録/検索アプリケーションを作成してみました。リレーショナル・データベースとJavaクラスのミスマッチを意識する必要がなくなり,コードがすっきりすることがおわかりいただけたでしょう。

 Hibernateは,今回ご紹介した以外にも様々な機能を持っています。本稿をきっかけに,ぜひそうした魅力ある機能にも触れてみてください。

山田 祥寛(やまだ よしひろ)

千葉県鎌ヶ谷市在住のフリーライター(http://www.wings.msn.to/