目次
表目次
ImplessDAOとは、JDBCの面倒なコードを記述せずにDBへアクセスするためのライブラリです。 名前も、IMPlementation-LESS DAOから来てます。 DBアクセスのためのライブラリは既にいくつもありますが、ImplessDAOは次のような目標で設計されています。
XMLの設定ファイルは使わない。EclipseなどのIDEに特別なプラグインを追加しなくても不自由なく開発が行えます。
DBの機能を最大限に活用することを妨げない。実際のアプリケーションではDBMSの変更など滅多にないので、もっとも適切なSQL文をプログラマが記述できます。
ImplessDAOをバイパスし直接JDBCを利用できる手段も用意し、開発者が最適な手段を利用できるようにする。効率あるいはその他の理由からImplessDAOの振る舞いが好ましくないときに、あなたは選択的かつシームレスにJDBCを直接利用したコードを記述できます。
ImplessDAOの一番簡単な使い方を示しましょう。
まず、net.sf.implessdao.AbstractDAOを継承して抽象クラスをを作成します。この抽象クラスでは、DBアクセスを行う抽象メソッド(ここではexecuteCreateCarTable)
を定義します。このメソッドにnet.sf.implessdao.Sqlアノーテーションを使って、このメソッドが呼ばれたときに実行したいSQLを指定します。
public abstract class CarDAO extends net.sf.implessdao.AbstractDAO {
@Sql(sql="create table car(ID INT PRIMARY KEY, name VARCHAR(32) NOT NULL)")
public abstract void executeCreateCarTable();
}
次に、java.sql.Connectionのインスタンスを取得するためのファクトリインスタンスを生成します。
ImplessDAOにはjava.sql.DriverManagerを利用したファクトリクラスnet.sf.implessdao.DriverManagerConnectionFactoryと
JNDIから取得したデータソースを利用したファクトリクラスnet.sf.implessdao.DataSourceConnectionFactoryがあらかじめ用意されています。
後は、先ほど作った抽象クラス(CarDAO)のクラスオブジェクトとコネクションファクトリーを引数に、net.sf.implessdao.DAOFactoryのcreateWithCompletionメソッドを呼び出します。
結果として得られるCarDAOのインスタンスは、抽象メソッドであったexecuteCreateCarTableメソッドがSqlアノーテーションで指定されたSQLを実行する
ように補完されています。そのため、executeCreateCarTableメソッドを呼び出すことができます。
IConnectionFactory connectionFactory = DriverManagerConnectionFactory .createConnectionFactory( "org.apache.derby.jdbc.EmbeddedDriver", "jdbc:derby:testdb;create=true", "", ""); CarDAO dao = DAOFactory.createWithCompletion(CarDAO.class, connectionFactory); dao.executeCreateCarTable();このように、抽象メソッドを実装する代わりにSQL文を指定することで、DBを操作することができます。
ImplessDAOは他のO-Rマッピングフレームワークと比較して、次のようなメリットがあります。
XMLなどを使った設定ファイルを利用せずすべてJavaで記述するため、コンパイル時にエラーが指摘される、デプロイに特別な配慮がいらない。
ImplessDAOの既定の動作を変更するあるいはバイパスする方法がいくつか用意されており、カスタマイズしやすい。また、ImplessDAOを使うか使わないかの二者択一ではなく、部分的活用もできる。
ImplessDAOを利用するには、ここ から最新のディストリビューションを取得します。 ディストリビューションは"implessdao-x.x.zip"というファイル名になっいます(x.xはバージョンを表します)。 また、ImplessDAOはOGNL 2.6.9とJakarta Commons - Logging 1.1と javassist 3.4に依存しているため、これらのjarファイルを入手しクラスパスに加えておきます。
入手したディストリビューションを展開します。\optというディレクトリの下にインストールするには、 次のようにします。
cd \opt
jar xvf \path\to\implessdao-x.x.zip
以上で、"\opt\implessdao-x.x"というディレクトリの直下に、"implessdao.jar"と含むいくつかのファイルやディレクトリが展開されます。
あとは、あなたのプログラムのコンパイルや実行時に、"\opt\implessdao-x.x\implessdao.jar"をクラスパスに加えるだけで、ImplessDAOを利用することができます。
ImplessDAOを利用するには、通常、クラスnet.sf.implessdao.DAOFactoryの
メソッドcreateWithCompletionを呼び出すだけです。
詳しくは、JavaDoc APIドキュメントと下記を参照してください。
ImplessDAOを使うには、を作成して大きく分けて次の3つを行うことにほかなりません。
DBにアクセスする抽象メソッド(以下「DBアクセス抽象メソッド」と呼ぶ)をnet.sf.implessdao.AbstractDAOのサブクラスで定義する
上記のDBアクセス抽象メソッドに対して、DBアクセス抽象メソッドが呼ばれたときに実行するSQLを指定する。
DBアクセス抽象メソッドを呼び出し実行結果を取得する。
ImplessDAOで補完される抽象メソッドは、以下の条件を満たすものです。
publicかつabstract
メソッド名が、execute, update, insert, delete, selectのいずれかで始まる
test()を呼び出すことで
実行時に検査されます。単体テストのコードから呼び出すようにするとよいでしょう。
DBアクセス抽象メソッドは、指定されたSQLを実行し結果を返すようImplessDAOにより補完されます。SQLの実行結果の返し方は、メソッド名が何で始まるかによって次のように決まっています。
表 2.1. DBアクセス抽象メソッドの戻り値
| メソッド名の先頭 | 可能な戻り値の型 | 戻り値の説明 |
|---|---|---|
| execute | void | - |
| insert | void/int/Integer | int/Integerを返す場合は、挿入/更新/削除したレコード数 |
| update | ||
| delete | ||
| select | net.sf.implessdao.IRSIteratable | selectした結果のレコード |
java.lang.RuntimeExceptonとして
投げられます。特にjava.sql.SQLException等は、net.sf.implessdao.DAORuntimeException
にラップされて投げられます。
DBアクセス抽象メソッドで実行するSQLを指定する一つ目の方法はnet.sf.implessdao.Sqlアノーテーションを用いることです。
例えば、下記のようにSQLを指定します。
@Sql(sql="select count(*) from someTable where ${{0:INTEGER}} <= col1 and col1 < ${{1:INTEGER}}")
public abstract IRSIteratable<Map<String,Object>> selectBetween(int lower, int upper);
「${{」と「}}」で囲まれた部分は、ImplessDAOによって「?」IN パラメータプレースホルダーに置換されます。
各IN パラメータプレースホルダーには値が設定されますが、どのような値をどのように設定するかは、「${{」と「}}」の
内側の記述に依存します。「${{」と「}}」の内側には、下記の形式で式とアクセッサ指定子を記述します。
式:アクセッサ指定子式には、0以上の整数、またはOGNL式を記述することができます。
表 2.2. 式の記述
| 書式 | 「?」IN パラメータプレースホルダーに設定される値 |
|---|---|
| 0以上の整数 | DBアクセス抽象メソッドの引数の値。式の値0:DBアクセス抽象メソッドの最初の引数、式の値1:二つ目の引数、以下... |
| OGNL式 | OGNL式の評価結果の値。DBアクセス抽象メソッドの引数は、OGNL式の中では、「args」配列としてアクセスできます。 したがって、${{0:INTEGER}}は、${{args[0]:INTEGER}}と等価です。OGNL式を使うとMapの値やJavaBeansのプロパティに簡単にアクセスできます。 |
net.sf.implessdao.IAccessor)とは、アプリケーションにおけるデータ表現と、
JDBCが提供するデータ表現の双方向の変換を抽象化したものです。このアクセッサを列挙したenum(net.sf.implessdao.IAccessorEnumを実装したenum)の
アクセッサ指定子には、このenum定数名を指定します。net.sf.implessdao.AbstractDAOのメソッドgetAccessorEnum()のデフォルトの実装は、
net.sf.implessdao.DefaultAccessorを返すようになっており、「INTEGER」などのはDefaultAccessorのenum定数名なのです。
メソッドgetAccessorEnum()をオーバーライドすることで、アクセッサを独自のものにカスタマイズすることもできます。
Sqlアノーテーションを利用して指定できるSQLは静的な文字列に限定されるので、DBアクセス抽象メソッドの引数の値に応じて SQLを変更したい場合には使えません。動的にSQLを生成するには、Sqlアノーテーションの代わりに、DBアクセス抽象メソッドと同じ引数を持ち、DBアクセス抽象メソッドのメソッド名の後ろに「SQL」を追加した、 Stringを返すメソッド定義します。
public String selectBetweenSQL(Integer lower, Integer upper) {
String sql = "select count(*) from someTable";
String sep = " where ";
if (lower != null) {
sql += sep + "${{0:INTEGER}} <= col1"; // IN パラメータプレースホルダーを使用
sep = " and ";
}
if (upper != null) {
sql += sep + "col1 < " + upper; // 文字列に埋め込み
}
return sql;
}
public abstract IRSIteratable<Map<String,Object>> selectBetween(Integer lower, Integer upper);
select以外で始まるDBアクセス抽象メソッドは、何も返さないかレコード数を返すかなので特に説明は必要ないでしょう。
selectで始まるDBアクセス抽象メソッドは、net.sf.implessdao.IRSIteratableを返します。
IRSIteratableは、java.sql.ResultSetをアプリケーションが扱いやすいjava.util.Iteratorを
通じて利用できるようにしたものです。IRSIteratableの実装は、レコードをどのように格納するのか(Mapに格納するのか、特定のJavaBeansに格納するのかなど)によっていくつか考えられます。
どのIRSIteratableを利用するかは、net.sf.implessdao.IRSIteratableFactoryを指定することで制御します。
IRSIteratableFactoryを指定するには2つの方法があります。一つ目の方法は、AbstractDAOのメソッドdefaultRIF()をオーバーライドすることです。
このメソッドの戻り値が、デフォルトで利用されるIRSIteratableFactoryとなります。二つ目の方法は、動的なSQLの指定と同じように、DBアクセス抽象メソッドと同じ引数で、DBアクセス抽象メソッド名の後ろに「RIF」を追加した、
IRSIteratableFactoryを返すメソッドを定義することです。当然、二つ目の方法が一つ目の方法より優されます。
AbstractDAOのデフォルトの実装では、net.sf.implessdao.DefaultRSIteratableFactoryのインスタンスを返すように実装されており、
DefaultRSIteratableFactoryは、カラム名をキーとしたMapにレコードの値を格納するnet.sf.implessdao.DefaultRSIteratableを
生成します。また、DefaultRSIteratableFactoryは、ResultSetからレコードの値を取り出すのにnet.sf.implessdao.DefaultDBAccessMapperを使用します。
DefaultDBAccessMapperは、ResultSetのメタデータから取得したカラムの型等の情報を元に、値を取り出します。
ImplessDAOのいくつかのクラスの背後には、関連するJDBCのオブジェクトが存在します。リソースの開放やエラーの解析を行うには、 時としてその関連を理解することが重要となります。
表 2.3. ImplessDAOのクラスと背後にあるJDBCクラス
| ImplessDAOのクラス | 背後にあるJDBCクラス |
|---|---|
| IDAO/AbstractDAO | java.sql.Connection |
| IRSIteratable/IRSIterator | java.sql.PreparedStatement, java.sql.ResultSet |
close()を呼び出し
リソースの開放を行うべきです。
AbstractDAOは、Connectionを提供するためのメソッドprepareConnection()を提供しています。
これを利用して、JDBCを直接操作するメソッドを定義することもできます。また、明示的なcommitを行うためのメソッドを次のように定義することもできます。
public void commit() throws SQLException {
prepareConnection().commit();
}