従来の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.