81.Daoの作り方サンプル
(通常の方法:SpringJDBC)

概要

Spring トランザクションはかなり強力で便利な機能です。

しかし、使用に関してはSpringトランザクションが働くようにDaoを作る必要があります。

でも、それはとても簡単です。

ここではHibernateやIBatisなどのO/Rマッピングを使用しないような、簡単なやり方を見て行きます。

しかしO/Rマッピングを使用する場合でもやり方はほぼ同じで、extendsするクラスが変わるぐらいです。

【注意事項 (2012.05.20追記)】

SimpleJdbcTemplateというクラスが存在していますが、Spring3.1以降ではdeprecatedされています。

JdbcTemplateを使うようにしましょう。

この記事ではSimpleJdbcTemplate で記事を書いてしまいましたが、以下のように読み替えてください。

?のプレースフォルダを使いたい場合 ⇒ JdbcTemplate

:name の名前プレースフォルダを使いたい場合 ⇒ NamedParameterJdbcTemplate

目標

まずは、ゴールを示しておきます。

会員の検索、更新などをするDaoを作ります。

ここではSpringJDBCを使用します。

厳密に言えばSpringJDBCはO/Rマッピングということになるかとは思いますが、普通のJDBCとしても使えるため

O/Rマッピングを使用しない場合というタイトルにしています。

サンプル

【Daoのサンプル】

public class MemberDaoTest extends JdbcDaoSupport {

//JDBCテンプレート

protected SimpleJdbcTemplate simpleTemplate;

//会員情報マッピング(selectのためのマッピングです)

protected class MemberRowMapper implements ParameterizedRowMapper<Member> {

@Override

public Member mapRow(ResultSet rs, int rowNum) throws SQLException {

Member mem = new Member();

mem.setId(rs.getString("id"));

mem.setName(rs.getString("name"));

mem.setAge(rs.getInt("age"));

return mem;

}

}

//初期化

protected void initDao()

{

this.simpleTemplate = new SimpleJdbcTemplate(getDataSource());

}

//selectサンプル

public List<Member> findMember(MemberSearchKey searchKey) {

//

String sql = "select * from t_member ";

String where = "";

if(searchKey.getId() != null){

where += " and id = :id";

}

if(searchKey.getName() != null){

where += " and name = :name";

}

if(searchKey.getAgeFrom() != -1){

where += " and age >= :ageFrom";

}

if(searchKey.getAgeTo() != -1){

where += " and age >= :ageTo";

}

if(!where.isEmpty()){

sql += " where " + where.substring(4);

}

//会員リスト

List<Member> memberList = this.simpleTemplate.query(

sql, new MemberRowMapper(), new BeanPropertySqlParameterSource(searchKey)

);

return memberList;

}

//更新サンプル(insertも同じ)

public void updateMember(Member member){

Assert.hasText(member.getId());

//SQL

String sql = "update member set name = :name, age = :age where id = :id";

this.simpleTemplate.update(sql, new BeanPropertySqlParameterSource(member));

}

}

メインのDaoサンプルクラスです。

ポイントは、JdbcDaoSupportを継承することです。

これによりSpringトランザクションを使用できるようになります。

DaoSupportは自作することもできますが、用意されたものを使用するのが良いでしょう。

<JdbcTemplate>

プレースフォルダを使用できるSpringJDBCのクラスです。

プレースフォルダは2種類が使用可能です。

・"?" を利用したJDBCでよく使用するプレースフォルダ(JdbcTemplate)

・":name"のように名前を使用するプレースフォルダ(NamedParameterJdbcTemplate )

このサンプルではせっかくなので名前を使用するプレースフォルダを使いました。

<BeanPropertySqlParameterSource>

以下、再掲:

List<Member> memberList = this.simpleTemplate.query(

sql, new MemberRowMapper(), new BeanPropertySqlParameterSource(searchKey)

);

query()の3つ目の引数は、Mapか、SqlParameterSourceのいずれかです。

ここでは、POJOをSqlParameterSourceに変換するクラスBeanPropertySqlParameterSourceを使用しました。

もし、"?"のプレースフォルダを使用したい場合は、可変長引数に値を順番に設定していきます。

<MemberRowMapper>

MemberRowMapperは、select結果のResultSetをMemberに変換するクラスで、上記で自作しています。

もし、Mapperを作りたくない場合はMapとして受け取ることもできます。以下に例を示します。

List<Map<String, Object>> memberList = this.simpleTemplate.queryForList(

sql, new BeanPropertySqlParameterSource(searchKey)

);

【Memberクラス】

public class Member {

private String id;

private String name;

private int age;

//getter / setterを以下に書く(ここでは省略)

}

【MemberSearchKeyクラス (検索のキーワードクラス)】

public class MemberSearchKey {

private String id;

private String name;

private int ageFrom=-1;

private int ageTo=-1;

public String getId() {

return id;

}

public void setId(String id) {

this.id = id;

}

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public int getAgeFrom() {

return ageFrom;

}

public void setAgeFrom(int ageFrom) {

this.ageFrom = ageFrom;

}

public int getAgeTo() {

return ageTo;

}

public void setAgeTo(int ageTo) {

this.ageTo = ageTo;

}

}

【Spring Context ファイル (宣言的トランザクションの記事を参照)】

<!-- Data Source (例えばPostgres)-->

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">

<property name="driverClassName" value="org.postgresql.Driver"/>

<property name="url" value="jdbc:postgresql://localhost/XXXX" />

<property name="username" value="XXX" />

<property name="password" value="XXX" />

</bean>

<!-- DAO -->

<bean id="memberDaoTest" class="dao.MemberDaoTest">

<property name="dataSource" ref="dataSource" />

</bean>

<!-- トランザクション管理 -->

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">

<property name="dataSource" ref="dataSource"/>

</bean>

<!-- 宣言的トランザクションの織り込み -->

<aop:config proxy-target-class="false">

<aop:advisor pointcut="execution(* business.service.*(..))" advice-ref="txAdvice" />

</aop:config>

<tx:advice id="txAdvice" >

<tx:attributes>

<tx:method name="find*" read-only="true" />

<tx:method name="*" propagation="REQUIRED" />

</tx:attributes>

</tx:advice>

宣言的トランザクションの記事と同じです。ほぼ再掲です。

ここでは説明は省略します。

これで、トランザクション制御をするときのDaoの作り方がわかったでしょうか?

注目すべきは、Daoのメソッド内に、SQL例外の try~catchがなくなっていることです。

地味ですが、いざとなると以外に楽です。

さらに詳細な内容については、以下の記事をご覧ください。

Created Date: 2010/01/12