連載
» 2004年11月17日 10時00分 公開

JavaTips 〜Javaプログラミング編:DbUtilsで結果セットをJavaBeansにマッピングする

[BULL,@IT]

基本的なデータベースアクセス方法の問題

 Javaから一般的なリレーショナルデータベース(以下、データベースと呼称)にアクセスするには、以下に示すようにjava.sqlパッケージのConnection、Statement、ResultSetを使うのが基本です。

InitialContext init = new InitialContext( );
DataSource ds = (DataSource)init.lookup("java:comp/env/jdbc/TestDB");
Connection con = ds.getConnection();
Statement st = con.createStatement();
ResultSet rs = st.executeQuery("select * from items;");
……// rsから結果を取得
rs.close(); // 終了処理
st.close(); // 終了処理
con.close();// 終了処理
init.close();// 終了処理


 この基本的な方法では、以下のような問題があります。

  • リソースリークを防ぐため、毎回決まりきった終了処理コードを記述しなければならない
  • 例外発生時にも終了処理コードが必ず実行されるように考慮しないといけない

 このように、従来の方法ではコードの記述量が多く、記述方法にも気を使わなければいけませんでした。この問題は、Jakarta DbUtilsを使うことで解決できます。

DbUtilsの概要

 DbUtilsはJakarta Commonsプロジェクトの産物であり、Javaからデータベースにアクセスするためのツールです。DbUtilsはデータベースアクセスの基本的なAPIであるConnection、Statement、ResultSetを使用することによるコード記述の煩雑性を緩和し、かつ高速に動作することを目的として開発されました。DbUtilsはこれら基本的なAPIの代わりとして使用します。

 DbUtilsの使い方の基本は以下のとおりです。QueryRunner#queryの戻り値がデータベース検索の結果になりますが、QueryRunner#queryの第2引数として渡すResultSetHandlerの内容により、QueryRunner#queryの戻り値の型が変化します。

import org.apache.commons.dbutils.QueryRunner;
importorg.apache.commons.dbutils.ResultSetHandler;
//中略
DataSource ds = …… //JNDI等を用いて取得
QueryRunner qr = new QueryRunner(ds);
ResultSetHandler rsh = …… //ResultSetHandlerの継承クラスのインスタンス
戻り値の型 result = (戻り値の型)qr.query("SELECT ...", rsh);


 DbUtilsのダウンロードはhttp://jakarta.apache.org/commons/dbutils/downloads.htmlからできます。執筆時点の最新版はバージョン1.0です。ダウンロードしたzipファイルを展開して出てきたcommons-dbutils-1.0.jarをクラスパスに通すことでjavaコードから使用可能になります。

DbUtilsで結果セットをJavaBeansにマッピングする

 DbUtilsでは、QueryRunner#queryの第2引数として、org.apache.commons.dbutils.handlersパッケージのBeanHandlerまたはBeanListHandlerのインスタンスを渡すことで、データベースを検索した結果セットを自動的にJavaBeansにマッピングすることができます。これを利用するとさらにコードの記述量を削減することができます。BeanHandlerとBeanListHandlerの違いは以下のとおりです。

BeanHandlerとBeanListHandlerの違い
DbUtilsのクラス 機能 QueryRunner#query の戻り値の型
BeanHandler 最初のレコードのデータを、コンストラクタの引数に渡したJavaBeansクラスのインスタンスに格納し取得する コンストラクタの引数に渡したJavaBeansクラス
BeanListHandler BeansHandlerの全レコード対応版。全レコードについてBeanHandlerを適用し、得られた全JavaBeansインスタンスをListとして取得する List(個々の要素はコンストラクタの引数に渡したJavaBeansクラスのインスタンス)

 BeanHandlerまたはBeanListHandlerを用いて、データベースを検索した結果セットをJavaBeansにマッピングするには、データベースのテーブルのカラムとJavaBeansのプロパティとの間で型と名前(大文字小文字は同一視される)をそろえておく必要があります。例えばItems.sqlで定義されるテーブルITEMSに格納されるデータをJavaBeansにマッピングするには、MyBean.javaのようにJavaBeansを定義します。

Items.sql
CREATE TABLE ITEMS
( ID INTEGER PRIMARY KEY,
NAME VARCHAR(255) NOT NULL
);


MyBean.java
package mybean;

public class MyBean {
  private int id;
  private String name;
  public void setId(int id) { this.id = id; }
  public int getId() { return id; }
  public void setName(String name) { this.name = name; }
  public String getName() { return name; }
}


 BeanListHandlerを使用して、データベースにアクセスし、テーブルITEMSに格納されている全データをMyBean.javaにより定義されるJavaBeansとして取得するjspの例をBeanListHandlerSample.jspとして示します。なお、前述したMyBean.javaのクラスファイルを含んだjarファイルと、DbUtilsのcommons-dbutils-1.0.jarがtomcat上のアプリケーションから参照可能になっており、DataSourceはJNDI名「java:comp/env/jdbc/TestDB」で取得できるものとします。tomcatでJNDI名を設定する方法は、「JNDI活用でデータソース管理を一元化する」を参照してください。

 BeanListHandlerSample.jspを見ると分かるように、わずか3行で目的の処理ができています。終了処理もInitialContextだけであり、コードもすっきりしているのが分かります。

BeanListHandlerSample.jsp
<%@ page contentType="text/html; charset=Windows-31J"
import="java.util.List,
java.util.Iterator,
javax.naming.InitialContext,
javax.sql.DataSource,
javax.naming.Context,
org.apache.commons.dbutils.QueryRunner,
org.apache.commons.dbutils.handlers.BeanListHandler,
org.apache.commons.dbutils.ResultSetHandler,
mybean.MyBean" %>
<%
InitialContext init = new InitialContext();
DataSource ds = (DataSource)init.lookup("java:comp/env/jdbc/TestDB");

QueryRunner qr = new QueryRunner(ds);
ResultSetHandler rsh = new BeanListHandler(MyBean.class);//結果を格納するJavaBeansを指定

//SQLを実行し、結果の各行に対応するMyBeanインスタンスを生成して各カラムの値をセットし、リストとして返す
List list = (List)qr.query("SELECT * FROM ITEMS", rsh);
%> 
<html>
  <head><title>DbUtils BeanListHandler sample</title></head>
    <body>

     <table border>
      <tr><th>ID</th><th>Name</th></tr>
      <%
      for (Iterator i = list.iterator(); i.hasNext(); ) {
        MyBean bean = (MyBean)i.next();
        %> 
        <tr><td><%= bean.getId() %></td>
        <td><%= bean.getName() %></td></tr>
        <%
      }
      init.close(); 
      %> 
    </table>
  </body>
</html> 


実行結果
実行結果

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。