従来のDB操作の場合、業務ロジック内にコネクションの取得/解放処理やSQL文を記述する必要がありました。そのため、下記のデメリットがありました。
・コネクションの解放漏れによるWebアプリケーションサーバのコネクションの枯渇の恐れがある
・SQL文の変更が容易ではない
TERASOLUNAのDAOを用いたデータベース操作では、ロジック上にコネクションに関する記述はなく、SQLはXMLファイルに記述します。これらにより下記のメリットがあります。
・コーディングによるバグ混入を防止できる
・SQL文の変更が容易
try {
// データソースからConnectionを取得
con = ds.getConnection();
// Statementを取得
stmt = con.createStatement();
// 検索するSQL文を作成
String sql = "SELECT TEST_COL1, TEST_COL2 FROM TEST_TABLE";
// クエリーを実行して結果セットを取得
ResultSet rs = stmt.executeQuery(sql);
while(rs.next()){
String col1 = rs.getString("TEST_COL1");
String col2 = rs.getString("TEST_COL2");
// 略
}
} catch (Exception e) {
// 略
} finally {
try {
if (stmt!=null) {stmt.close();}
// コネクションの開放
if (con!=null) {con.close();}
} catch (Exception e) {
// 略
}
}
TERASOLUNAのDAOには用途ごとに特化した機能を持つインターフェイスが提供されています。また、iBATISを利用したデフォルト実装が提供されています。
| DAO名 | インターフェイス名 | 実装クラス名 | 実行できるSQL |
|---|---|---|---|
| 参照系DAO | QueryDAO | QueryDAOiBatisImpl | SELECT文 |
| 更新系DAO | UpdateDAO | UpdateDAOiBatisImpl | INSERT文 UPDATE文 DELETE文 |
| ストアドプロシージャDAO | StoredProcedureDAO | StoredProcedureDAOiBatisImpl | ストアドプロシージャ |
| 表4 DAOインターフェイス | |||
TERASOLUNAのDAOを利用する場合はSQL設定ファイルに対応するDAO入出力クラスを定義する必要があります。
連載第2回の際に作成したアプリケーションを修正する形で実装します(下記リストはインデックスになっています)。
sqlMap.xmlファイルの定義は「webapps\WEB-INF\sqlMapConfig.xml」にあります。
USER_LISTテーブルに対し、画面から入力されたidとnameを登録するSQLを<insert>要素の値に定義しています。このとき、parameter属性にはSQLのVALUESに指定するフィールド(#で囲む)を持つクラスを指定します。また、USER_LISTテーブルからidとnameを取得するSQLを<select>要素の値に定義しています。このとき、parameter属性に条件文に利用するフィールドを持つクラスを、resultClass属性には発行されたSQLの結果を格納するフィールドを持つクラスを指定します。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-2.dtd">
<sqlMap namespace="user">
<insert id="addUser" parameterClass="sample.AddUserDaoInput">
INSERT INTO user_list (id, name) VALUES (#addUserId#,#addUserName#)
</insert>
<select id="selectUser" parameterClass="sample.AddUserDaoInput"resultClass="sample.SelectUserDaoOutput">
SELECT id as "userId",name as "userName" FROM user_list WHERE id = #addUserId#
</select>
</sqlMap>
上記で定義されたSQLを呼び出すDAOを業務ロジック内に定義します。
DAOの定義として、QueryDAOとUpdateDAOのフィールドを定義します。このときspringによるセッターインジェクションのために各フィールドのセッターを定義します。画面から入力されたfirstTermとsecondTermを業務入力クラス(ConcatInput)から取り出し、DAO入力クラス(AddUserDaoOutput)へ格納します。このDAO入力クラス(AddUserDaoInput)を引数として、DBへの登録処理(updateDAO)を実行します。このとき、sql設定ファイル(sqlMap.xml)における<insert>要素のid属性を指定します。
次に、上記のDAO入力クラス(AddUserDaoInput)を引数として、DBからの参照処理(queryDAO)を実行し、返り値を、DAO出力クラス(SelectUserDaoOutput)に格納します。業務出力オブジェクトの生成以降の流れは連載第2回の記事と同様となりますので割愛します。
package sample;
import jp.terasoluna.fw.dao.QueryDAO;
import jp.terasoluna.fw.dao.UpdateDAO;
import jp.terasoluna.fw.service.thin.BLogic;
import jp.terasoluna.fw.service.thin.BLogicResult;
public class ConcatBLogic implements BLogic<ConcatInput>{
//DAOの定義
protected QueryDAO queryDAO;
protected UpdateDAO updateDAO;
public void setQueryDAO(QueryDAO queryDAO) {
this.queryDAO = queryDAO;
}
public void setUpdateDAO(UpdateDAO updateDAO) {
this.updateDAO = updateDAO;
}
public BLogicResult execute(ConcatInput input) {
//業務処理(DB登録)の実行
AddUserDaoInput addUserDaoInput = new AddUserDaoInput();
addUserDaoInput.setAddUserId(input.getFirstTerm());
addUserDaoInput.setAddUserName(input.getSecondTerm());
this.updateDAO.execute("addUser", addUserDaoInput);
//業務処理(DB参照)の実行
SelectUserDaoOutput selectUser = this.queryDAO.
executeForObject("selectUser", addUserDaoInput,
SelectUserDaoOutput.class);
String resultTerm = selectUser.getUserId() + " " +
selectUser.getUserName();
//業務出力オブジェクトを生成
ConcatOutput output = new ConcatOutput();
output.setResultTerm(resultTerm);
//結果オブジェクトの生成
BLogicResult result = new BLogicResult();
result.setResultString("success");
result.setResultObject(output);
return result;
}
}
Bean定義ファイルを以下のように修正し、業務ロジックとDAOを関連付けます。
<!-- 下記が変更部分で、それ以外の部分は省略 -->
<bean class="sample.ConcatBLogic" id="concatBLogic"
scope="singleton">
<property name="queryDAO" ref="queryDAO" />
<property name="updateDAO" ref="updateDAO" />
</bean>
DAO入出力のDTOクラスを定義します。
package sample;
public class AddUserDaoInput {
private String addUserId;
private String addUserName;
//以下省略、ゲッター、セッターの記述
}
package sample;
public class SelectUserDaoOutput {
private String userId;
private String userName;
//以下省略、ゲッター、セッターの記述
}
TERASOLUNAフレームワークではトランザクション管理(コミットやロールバック)にSpringのAOPを用いて行うことができます。そのため、開発者がトランザクションコードを実装する必要がありません。今回の例では、業務処理(BLogic)単位でトランザクションを管理します。
AOPの設定に関してですが、commonContext.xmlにAOPの設定を追記します。<aop:pointcut>要素のexpression属性に「bean(*BLogic)」と指定します。これによりBean定義IDの接尾辞がBLogicのBeanに対してトランザクションが適用されます。また、
次に、トランザクションインターセプタの設定ですが、
<!-- AOPの設定 -->
<aop:config>
<!-- 業務ロジック(*BLogic)単位でのトランザクション設定 -->
<aop:pointcut id="blogicBeans" expression="bean(*BLogic)"/>
<aop:advisor
pointcut-ref="blogicBeans"
advice-ref="transactionInterceptor"/>
</aop:config>
<!-- 略 -->
<!-- データソース設定 -->
<bean id="TerasolunaSampleDataSource"
class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName">
<value>java:comp/env/jdbc/TerasolunaSampleDataSource</value>
</property>
</bean>
<!-- トランザクションマネージャの設定 -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource">
<ref bean="TerasolunaSampleDataSource"/>
</property>
</bean>
<!-- トランザクションインタセプタの設定 -->
<tx:advice id="transactionInterceptor" >
<tx:attributes>
<!-- 対象メソッド名を「*」とする -->
<tx:method name="*" propagation="REQUIRED"
rollback-for="java.lang.Exception"/>
</tx:attributes>
</tx:advice>
<!-- 略 -->
それでは、次ページで動作確認をしてみましょう。
Copyright © ITmedia, Inc. All Rights Reserved.