S2Daoのサンプルアプリ作成(オートコミットモード)
サンプルアプリの概要(トランザクション制御なしのオートコミットの場合)
「SAMPLE1テーブルに対する登録、更新、削除処理を行う簡単なサンプルアプリです。」
「SAMPLE1テーブルとMASTER1からの参照処理※を行う簡単なサンプルアプリです。」
※ SELECT S.ID, S.NAME, M.SALARY, M.UTIWAKE FROM SAMPLE1 S, MASTER1 M WHERE S.ID = M.MASTER_ID(+);
SAMPLE1テーブル
ID(PK) | NUMBER(2) |
NAME | VARCHAR2(10) |
MASTER1テーブル
MASTER_ID(PK) | NUMBER(2) |
SALARY | NUMBER(6) |
UTIWAKE | VARCHAR2(16) |
[開発環境]
- JDK1.5.0_13
- eclipse3.2
- Seasar2 2.4.20
- S2.4.20.zipを解凍し、各jarファイルにクラスパスを通す(詳細設定は他サイトを参考にして下さい)
- S2Dao 1.0.47
- s2-dao-1.0.47.zipを解凍し、各jarファイルにクラスパスを通す
[用意するもの]
- データベースに上記テーブルSAMPLE1、MASTER1をCREATE
- Seasar2コンテナからDaoを取り出しDBの参照を行うメインクラスDBQuery.java
- テーブルとの関連付けに使用するJavaBeans(SAMPLE1テーブル用)…MemberInfo.java
- テーブルとの関連付けに使用するJavaBeans(MASTER1テーブル用)…MasterInfo.java
- Daoインタフェース(SAMPLE1テーブル用)…MemberInfoDao.javaインタフェース
以下のdiconファイルはクラスパスの通っている場所に配備すること
- j2ee.dicon(データベースとの接続設定を記述)
- 自作.dicon(Daoの注入に使用)
[処理の流れその1]
入力値チェックを行う場合
1.メインクラスのDBQueryThreadでSeasar2コンテナからSAMPLE1テーブル参照用のDaoコンポーネントを取得する。
↓
2.Daoのインタフェース経由でSAMPLE1テーブルのデータを参照する。
その際、SAMPLE1テーブルのIDとMASTER1テーブルのMASTER_IDをキーにテーブルが結合され、その結合データがリストの形式で返される。
↓
3.DBQueryThreadで、受け取ったリストをループで回し、テーブルの各カラムの値を取り出す。
DBQuery.java
package jp.co.companyname.app; import java.sql.SQLException; import java.util.List; import jp.co.companyname.dao.MemberInfo; import jp.co.companyname.dao.MemberInfoDao; import org.seasar.framework.container.S2Container; import org.seasar.framework.container.factory.S2ContainerFactory; import org.seasar.framework.exception.SQLRuntimeException; /** * S2コンテナとS2Daoを使用して、データベースの参照/更新を行います。 * 2008/1/16 * @author shimabukurot * */ public class DBQuery { public static void main(String[] args) { System.out.println(Thread.currentThread() + " --------- S2Daoテスト開始"); // ■1SQLごとにトランザクションが完結する制御(オートコミット) // S2コンテナからDaoコンポーネントを取得 S2Container container = S2ContainerFactory.create("自作.dicon"); MemberInfoDao dao = (MemberInfoDao) container.getComponent(MemberInfoDao.class); // [登録処理実行] // クエリ実行時にorg.seasar.framework.exception.SQLRuntimeExceptionが // 発生すると処理はtry-catch句で囲まれていない限りそこで終了します。 dao.insert(new MemberInfo(5, "五郎")); dao.insert(new MemberInfo(6, "六郎")); dao.insert(new MemberInfo(7, "七郎")); dao.insert(new MemberInfo(8, "八郎")); System.out.println(Thread.currentThread() + " --------- S2Dao登録テスト終了"); // [更新処理実行] dao.update(new MemberInfo(4, "四郎update")); System.out.println(Thread.currentThread() + " --------- S2Dao更新テスト終了"); // [削除処理実行] dao.delete(new MemberInfo(4, "四郎del")); System.out.println(Thread.currentThread() + " --------- S2Dao削除テスト終了"); // [参照処理実行] List mInfoList = dao.findAll(); for (int i = 0; i < mInfoList.size(); i++) { MemberInfo mInfo = (MemberInfo) mInfoList.get(i); // 該当カラムにデータがない場合 // 該当カラムがNUMBER型の場合は0、 // 該当カラムがVARCHAR2型の場合はnullが返ります。 System.out.println(Thread.currentThread() + "[SAMPLE1.id] " + mInfo.getId()); System.out.println(Thread.currentThread() + "[SAMPLE1.name] " + mInfo.getName()); System.out.println(Thread.currentThread() + "[MASTER1.salary]" + mInfo.getMasterInfo().getSalary()); System.out.println(Thread.currentThread() + "[MASTER1.utiwake]" + mInfo.getMasterInfo().getUtiwake()); } System.out.println(Thread.currentThread() + " --------- S2Dao参照テスト終了"); } }
MemberInfo.java
package jp.co.companyname.dao; public class MemberInfo { /* * [構文] * スキーマ名.テーブル名 * テーブル名だけでも可 */ public static final String TABLE = "スキーマ名.SAMPLE1"; // 定数アノテーション //public static final String id_COLUMN = "ID"; //public static final String name_COLUMN = "NAME"; /** * * RELNOをString型にするとjava.lang.IllegalArgumentExceptionで落ちます。 * RELNO定数は、N:1マッピングの連番になるので以下のように0から付けていく必要があります。 */ public static final int masterInfo_RELNO = 0; /** * [構文] * * エンティティ名(JavaBeansのクラス名:先頭は小文字)_RELKEYS = "N側のテーブルのカラム名: 1側のテーブルのカラム名"; * ※エンティティ名を間違うとテーブルの結合ができません。 */ public static final String masterInfo_RELKEYS = "ID:MASTER_ID"; private int id; private String name; private MasterInfo abc;// 結合対象のテーブルを表すエンティティ(変数名は任意でよい) // コンストラクタ public MemberInfo(){} public MemberInfo(int id, String name) { this.id = id; this.name = name; } public MemberInfo(int id, String name, int salary, MasterInfo masterInfo) { this.id = id; this.name = name; this.abc = masterInfo; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public MasterInfo getMasterInfo() { return abc; } public void setMasterInfo(MasterInfo masterInfo) { this.abc = masterInfo; } }
MasterInfo.java
package jp.co.companyname.dao; public class MasterInfo { /* * [構文] * スキーマ名.テーブル名 * テーブル名だけでも可。 */ public static final String TABLE = "スキーマ名.MASTER1"; private int masterId; private int salary; private String utiwake; // 空コンストラクタ(DIコンテナがインスタンス生成を行うために必須) public MasterInfo(){}; public MasterInfo(int id, int salary) { this.masterId = id; this.salary = salary; } public int getSalary() { return salary; } public void setSalary(int salary) { this.salary = salary; } public int getMasterId() { return masterId; } public void setMasterId(int masterId) { this.masterId = masterId; } public String getUtiwake() { return utiwake; } public void setUtiwake(String utiwake) { this.utiwake = utiwake; } }
MemberInfoDao.javaインタフェース
package jp.co.companyname.dao; import java.util.List; /* * MemberInfoから情報を取得するDao。 * 実装はDIコンテナが行います。 * よって自分で実装クラスの * 宣言をする必要はありません。 */ public interface MemberInfoDao { public static final Class BEAN = MemberInfo.class; public int insert(MemberInfo mInfo); public int update(MemberInfo mInfo); public int delete(MemberInfo mInfo); public void doSomething(); public String getText(); public List findAll(); }
j2ee.dicon(抜粋)
<!-- for Oracle --> <component name="xaDataSource" class="org.seasar.extension.dbcp.impl.XADataSourceImpl"> <property name="driverClassName"> "oracle.jdbc.driver.OracleDriver" </property> <property name="URL"> "jdbc:oracle:thin:@ホスト名:ポート番号:サービス名" </property> <property name="user">"TEST"</property> <property name="password">"TEST"</property> <initMethod name="addProperty"> <arg>"includeSynonyms"</arg> <arg>"true"</arg> </initMethod> </component>
自作.dicon
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.3//EN" "http://www.seasar.org/dtd/components23.dtd"> <components> <include path="dao.dicon" /> <component name="MemberInfoDaoDesu" class="jp.co.companyname.dao.MemberInfoDao"> <aspect>dao.interceptor</aspect> </component> </components>
おまけ:テスト用の自作.dicon
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE components PUBLIC "-//SEASAR//DTD S2Container 2.3//EN" "http://www.seasar.org/dtd/components23.dtd"> <components> <include path="dao.dicon" /> ★MemberInfoDaoTestのモックテスト用。ダミーのgetTextの戻り値を用意。getTextはメソッド名 <component name="MemberInfoDaoDesu" class="jp.co.companyname.dao.MemberInfoDao"> <aspect> <component class="org.seasar.framework.aop.interceptors.MockInterceptor"> <initMethod name="setReturnValue"> <arg>"getText"</arg> <arg>"テスト用のダミーテキストです。dummy."</arg> </initMethod> </component> </aspect> </component> </components>