ブログ アーカイブ

自己紹介

本ブログをご覧いただき、ありがとうございます。
株式会社ヒューマンインタラクティブテクノロジー(HIT)の技術グループ担当者です。

弊社ホームページ
ラベル mybatis の投稿を表示しています。 すべての投稿を表示
ラベル mybatis の投稿を表示しています。 すべての投稿を表示

2014年4月1日火曜日

MyBatisで遊んでみる(3) 第三章 MyBatis実装サンプル

どうも、トムです。
前準備は終わりましたので第三章ではMyBatisを実装してみます。


第三章 MyBatis実装サンプル

必要なライブラリは第二章を参照してください。
本稿では第二章までの構築が完了している前提で進みます。

前回はmybatis-generatorで以下のファイルが自動生成されました。


mybatis-config.xmlの設定

まずはMyBatisを利用するために設定ファイルを記述します。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
  <settings>
    <!-- mybatisログ出力用 -->
    <setting name="logImpl" value="LOG4J"/>
  </settings>
  <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <!-- データソース -->
      <dataSource type="POOLED">
        <property name="driver" value="org.postgresql.Driver"/>
        <property name="url" value="jdbc:postgresql://192.168.100.100:5432/test"/>
        <property name="username" value="mybatisuser"/>
        <property name="password" value="password"/>
      </dataSource>
    </environment>
  </environments>
  <mappers>
    <!-- Mapperファイルのパスを記述 -->
    <mapper resource="jp/hit/sample/mybatis/mapper/EmpMapper.xml"/>
    <mapper resource="jp/hit/sample/mybatis/mapper/DeptMapper.xml"/>
  </mappers>
</configuration>

今回コンソールでMyBatisが発行したSQLを確認したいのでsetting要素でLog4jでログ出力出来るように設定しています。
ロギング自体は指定しだいでLog4jの他にSLF4JやLog4j2なども使用可能です。
詳細は公式のリファレンスを参照してください。

dataSource要素ではJDBCパラメータ、mappers要素では実際のMapperのパスを記載します。



log4j.xmlの設定

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" >

  <appender name="stdout" class="org.apache.log4j.ConsoleAppender">
     <param name="Target" value="System.out" />
     <layout class="org.apache.log4j.PatternLayout">
        <param name="ConversionPattern" value="%c{1} - %m%n" />
     </layout>
  </appender>

  <!-- SQLログを出力 -->
  <logger name="jp.hit.sample.mybatis.client" additivity="false">
    <level value="debug"/>
    <appender-ref ref="stdout"/>
  </logger>
  <!-- MyBatisSampleのデバッグログを出力 -->
  <logger name="jp.hit.sample.mybatis.logic" additivity="false">
    <level value="debug"/>
    <appender-ref ref="stdout"/>
  </logger>
  <root>
    <level value="info"/>
    <appender-ref ref="stdout"/>
  </root>
</log4j:configuration>
MyBatisが発行するSQLを確認するためにJava Client(jp.hit.sample.mybatis.client)以下のログレベルをDEBUGに設定してあります。




セッションの生成

MyBatisのセッション生成は次の実装で実現できます。
    package jp.hit.sample.mybatis.util;

import java.io.IOException;
import java.io.InputStream;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.log4j.Logger;

public class SessionUtil {
    private static Logger LOG = Logger.getLogger(SessionUtil.class);
    private static final String RESOURCE = "mybatis-config.xml";

    private SessionUtil() {
    }

    public static SqlSession createSession() {
        SqlSession session = null;
        try {
            InputStream is = Resources.getResourceAsStream(RESOURCE);
            SqlSessionFactory ssf = new SqlSessionFactoryBuilder().build(is);
            session = ssf.openSession(false);
        } catch (IOException e) {
            LOG.error(e.getMessage(), e);
        }
        return session;
    }
}
また、SqlSessionFactoryには以下6つのopenSessionメソッドが用意されており、用途に応じてセッションの生成を行う事が可能です。
SqlSession openSession()
SqlSession openSession(boolean autoCommit)
SqlSession openSession(Connection connection)
SqlSession openSession(TransactionIsolationLevel level)
SqlSession openSession(ExecutorType execType,TransactionIsolationLevel level)
SqlSession openSession(ExecutorType execType)
SqlSession openSession(ExecutorType execType, boolean autoCommit)
SqlSession openSession(ExecutorType execType, Connection connection)
今回のように引数を指定せずにセッションを生成した場合はautoCommit=false(自動コミット無効)の状態でセッションが生成されます。
JDBCのトランザクション分離レベルを指定してセッションを生成したい場合は以下のように記述します。
openSession(TransactionIsolationLevel.NONE); // トランザクション無効
openSession(TransactionIsolationLevel.READ_UNCOMMITTED);  // READ UNCOMMITTED (ダーティリード有、非再現リード有、ファントムリード有)
openSession(TransactionIsolationLevel.READ_COMMITTED); // READ COMMITTED (ダーティリード無、非再現リード有、ファントムリード有)
openSession(TransactionIsolationLevel.REPEATABLE_READ); // REPEATABLE READ (ダーティリード無、非再現リード無、ファントムリード有)
openSession(TransactionIsolationLevel.SERIALIZABLE); // SERIALIZABLE (ダーティリード無、非再現リード無、ファントムリード無)
SQLステートメントの実行モードを指定したい場合は以下のように記述します。
openSession(ExecutorType.SIMPLE); // デフォルト ステートメント実行のたびにPreparedStatementを作成します。
openSession(ExecutorType.REUSE); // PreparedStatementを再利用します。
openSession(ExecutorType.BATCH); // 全ての更新ステートメントをバッチ処理します。
TransactionIsolationLevelやExecutorTypeはDBやMyBatisのバージョンにより挙動が変わるので使用する際は注意が必要です。
例えば、postgreSQLの場合はREAD_UNCOMMITTEDを指定してもダーティリードは行われません。




SQLの発行

次に生成したセッションを利用して実際にMapperファイルに記載されたSQLを発行してみます。
MyBatisを利用したSQL発行は非常にシンプルに実装できます。
    private static Logger LOG = Logger.getLogger(MyBatisSample.class);

    private static EmpMapper empMapper;
    private static DeptMapper deptMapper;

    public static void main(String[] args) {
        // セッション作成
        SqlSession session = SessionUtil.createSession();
        // Mapperを取得
        empMapper = session.getMapper(EmpMapper.class);
        deptMapper = session.getMapper(DeptMapper.class);

        try {
            // EmpMapperに自動生成されたselectByPrimaryKeyクエリを利用したPK指定でのEmpテーブルへのselect発行
            EmpKey key = new EmpKey();
            key.setId(1); // id = 1
            key.setDeptId(1); // dept_id = 1
            LOG.debug("【SQL発行】jp.hit.sample.mybatis.client.EmpMapper.selectByPrimaryKey id = 1 and dept_id = 1");
            Emp emp = empMapper.selectByPrimaryKey(key);
            printEmp(emp); // 取得したEmpデータ出力


            // EmpMapperに自動生成されたExampleMapperを使用したselect発行
            EmpExample param = new EmpExample();
            List<string> names = Arrays.asList("Bravo", "Charlie", "HIT tom");
            param.createCriteria().andNameIn(names); // IN ('Bravo','Charlie','HIT tom')
            param.setOrderByClause("dept_id desc"); // Order by dept_id desc
            LOG.debug("【SQL発行】selectByExample in ('Bravo','Charlie','HIT tom') order by dept_id desc");
            List<emp> empList = empMapper.selectByExample(param);
            printEmp(emp); // 取得したEmpデータ出力


            // Insert
            Emp insertEntity = new Emp();
            insertEntity.setId(5);
            insertEntity.setName("HIT tom");
            insertEntity.setDeptId(2);
            insertEntity.setTel("03-5225-0530");
            LOG.debug("【SQL発行】Insert Emp");
            empMapper.insert(insertEntity);


            // Insert結果取得
            empList = empMapper.selectByExample(param);
            LOG.debug("【SQL発行】selectByExample in ('Bravo','Charlie','HIT tom') order by dept_id desc");
            printEmp(emp); // 取得したEmpデータ出力

        } finally {
            // 実行前の状態にロールバックする
            session.rollback();
            // セッションを閉じる
            session.close();
        }
    }


    /**
     * Empの中身をダンプする
     * @param empList
     */
    private static void printEmp(List<emp> empList) {
        for (Emp emp : empList) {
            printEmp(emp);
        }
    }

    private static void printEmp(Emp emp) {
        if (emp != null) {
            LOG.debug("【Result】 " + "id:" + emp.getId() + ", Name:" + emp.getName() + ", Dept:"
                    + String.valueOf(emp.getDeptId()) + ", Tel:" + emp.getTel());
        }
    }

サンプル実行前のテーブルデータは以下の通り
select * from my.dept;
 id |    name
----+------------
  1 | Foundation
  2 | Sales
  3 | System

select * from my.emp;
 id | dept_id |  name   |     tel
----+---------+---------+--------------
  1 |       1 | Alfa    | 111-111-1111
  2 |       1 | Aileen  | 123-123-1234
  3 |       3 | Bravo   | 222-222-2222
  4 |       2 | Charlie | 333-333-3333

サンプルを実行すると以下の結果が得られます。
MyBatisSample - 【SQL発行】jp.hit.sample.mybatis.client.EmpMapper.selectByPrimaryKey id = 1 and dept_id = 1
selectByPrimaryKey - ooo Using Connection [org.postgresql.jdbc4.Jdbc4Connection@7bfb4d34]
selectByPrimaryKey - ==>  Preparing: select id, dept_id, name, tel from my.emp where id = ? and dept_id = ? 
selectByPrimaryKey - ==> Parameters: 1(Integer), 1(Integer)
selectByPrimaryKey - <==      Total: 1
MyBatisSample - 【Result】 id:1, Name:Alfa, Dept:1, Tel:111-111-1111
MyBatisSample - 【SQL発行】selectByExample in ('Bravo','Charlie','HIT tom') order by dept_id desc
selectByExample - ooo Using Connection [org.postgresql.jdbc4.Jdbc4Connection@7bfb4d34]
selectByExample - ==>  Preparing: select 'false' as QUERYID, id, dept_id, name, tel from my.emp WHERE ( name in ( ? , ? , ? ) ) order by dept_id desc 
selectByExample - ==> Parameters: Bravo(String), Charlie(String), HIT tom(String)
selectByExample - <==      Total: 2
MyBatisSample - 【Result】 id:3, Name:Bravo, Dept:3, Tel:222-222-2222
MyBatisSample - 【Result】 id:4, Name:Charlie, Dept:2, Tel:333-333-3333
MyBatisSample - 【SQL発行】Insert Emp
insert - ooo Using Connection [org.postgresql.jdbc4.Jdbc4Connection@7bfb4d34]
insert - ==>  Preparing: insert into my.emp (id, dept_id, name, tel) values (?, ?, ?, ?) 
insert - ==> Parameters: 5(Integer), 2(Integer), HIT tom(String), 03-5225-0530(String)
insert - <==    Updates: 1
MyBatisSample - 【SQL発行】selectByExample in ('Bravo','Charlie','HIT tom') order by dept_id desc
selectByExample - ooo Using Connection [org.postgresql.jdbc4.Jdbc4Connection@7bfb4d34]
selectByExample - ==>  Preparing: select 'false' as QUERYID, id, dept_id, name, tel from my.emp WHERE ( name in ( ? , ? , ? ) ) order by dept_id desc 
selectByExample - ==> Parameters: Bravo(String), Charlie(String), HIT tom(String)
selectByExample - <==      Total: 3
MyBatisSample - 【Result】 id:3, Name:Bravo, Dept:3, Tel:222-222-2222
MyBatisSample - 【Result】 id:4, Name:Charlie, Dept:2, Tel:333-333-3333
MyBatisSample - 【Result】 id:5, Name:HIT tom, Dept:2, Tel:03-5225-0530

サンプル実行後もロールバックが正常に働きテーブルデータが変化しない事が確認出来ます。
select * from my.dept;
 id |    name
----+------------
  1 | Foundation
  2 | Sales
  3 | System

select * from my.emp;
 id | dept_id |  name   |     tel
----+---------+---------+--------------
  1 |       1 | Alfa    | 111-111-1111
  2 |       1 | Aileen  | 123-123-1234
  3 |       3 | Bravo   | 222-222-2222
  4 |       2 | Charlie | 333-333-3333





任意のMapper作成

自動生成されたMapperの利用を確認出来たら次に新規にMapperファイルを作成して任意のSQLを発行させてみましょう。

まず、Mapperファイルと同一のパッケージ内に任意のMapper(今回はEmpDeptSqlMap.xml)を作成します。

MyBatisのマッピングは以下の基準で紐付けが行われているのですが、今回は分かりやすいように敢えてMapperの名前を「~Mapper」ではなく「SqlMap」に変えています。
  • Mapperのinterfaceクラス名 = Mapperファイルのnamespace
  • Mapperのinterfaceクラスのメソッド名 = MapperファイルのSQLID
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="jp.hit.sample.mybatis.client.EmpDeptSqlMap" >
  <resultMap id="EmpDeptResultMap" type="jp.hit.sample.mybatis.entity.EmpDept" >
    <id column="emp_id" property="empId" jdbcType="INTEGER" />
    <id column="dept_id" property="deptId" jdbcType="INTEGER" />
    <id column="dept_name" property="deptName" jdbcType="VARCHAR" />
    <result column="emp_name" property="empName" jdbcType="VARCHAR" />
    <result column="tel" property="tel" jdbcType="VARCHAR" />
  </resultMap>

  <!--
    resultMapを定義せずにresultTypeを指定し
    <select id="selectEmpJoinDept" resultType="jp.hit.sample.mybatis.entity.EmpDept" parameterType="jp.hit.sample.mybatis.entity.EmpDept">
    のように直接Entityクラスを戻り値に指定することも可能ですが
    内部的に余計なマッピング処理が発生する為、resultMapでjdbcTypeを定義することが推奨されています。
   -->
  <select id="selectEmpJoinDept" resultMap="EmpDeptResultMap" parameterType="jp.hit.sample.mybatis.entity.EmpDept">
    SELECT
         emp.id      AS emp_id
        ,emp.dept_id AS dept_id
        ,dept.name   AS dept_name
        ,emp.name    AS emp_name
        ,emp.tel     AS tel
    FROM my.emp emp
    LEFT JOIN my.dept dept ON emp.dept_id = dept.id

    <!--
         <where> 要素は、内包するタグのどれかが結果を返すときだけ "WHERE" を挿入します。
         更に、内包するタグから返された結果が "AND" または "OR" で始まっていた場合はこれを削除します。
         以下の例の場合 empId、deptId、empName、deptName、tel 全てがnullの場合 where要素が削除されます。
     -->
    <where>
      <if test="empId != null">
        AND emp.id = #{empId,jdbcType=INTEGER}
      </if>
      <if test="deptId != null">
        AND emp.dept_id = #{deptId,jdbcType=INTEGER}
      </if>
      <if test="empName != null">
        AND emp.name LIKE #{empName,jdbcType=VARCHAR}
      </if>
      <if test="deptName != null">
        AND dept.name LIKE #{deptName,jdbcType=VARCHAR}
      </if>
      <if test="tel != null">
        AND emp.tel = #{tel,jdbcType=VARCHAR}
      </if>
    </where>
    ORDER BY emp.id
  </select>

</mapper>
MyBatisによる動的SQLの記法については公式リファレンスを参照してください。
Mapperファイルには静的SQLをそのまま記述することも可能です。


次にmybatis-config.xmlにMapperファイルのパスを追記します。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
  <settings>
    <!-- mybatisログ出力用 -->
    <setting name="logImpl" value="LOG4J"/>
  </settings>
  <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <!-- データソース -->
      <dataSource type="POOLED">
        <property name="driver" value="org.postgresql.Driver"/>
        <property name="url" value="jdbc:postgresql://192.168.245.131:5432/test"/>
        <property name="username" value="mybatisuser"/>
        <property name="password" value="password"/>
      </dataSource>
    </environment>
  </environments>
  <mappers>
    <!-- Mapperファイルのパスを記述 -->
    <mapper resource="jp/hit/sample/mybatis/mapper/EmpMapper.xml"/>
    <mapper resource="jp/hit/sample/mybatis/mapper/DeptMapper.xml"/>
    <mapper resource="jp/hit/sample/mybatis/mapper/EmpDeptSqlMap.xml"/>
  </mappers>
</configuration>

Entityを作成します。
package jp.hit.sample.mybatis.entity;

public class EmpDeptKey {
    private Integer empId;
    private Integer deptId;

    public Integer getEmpId() {
        return empId;
    }
    public void setEmpId(Integer empId) {
        this.empId = empId;
    }
    public Integer getDeptId() {
        return deptId;
    }
    public void setDeptId(Integer deptId) {
        this.deptId = deptId;
    }
}
package jp.hit.sample.mybatis.entity;

public class EmpDept extends EmpDeptKey {
    private String empName;
    private String deptName;
    private String tel;

    public String getEmpName() {
        return empName;
    }
    public void setEmpName(String empName) {
        this.empName = empName;
    }
    public String getDeptName() {
        return deptName;
    }
    public void setDeptName(String deptName) {
        this.deptName = deptName;
    }
    public String getTel() {
        return tel;
    }
    public void setTel(String tel) {
        this.tel = tel;
    }
}

Mapperのinterfaceクラスを作成します。
package jp.hit.sample.mybatis.client;

import java.util.List;

import jp.hit.sample.mybatis.entity.EmpDept;

public interface EmpDeptSqlMap {
    /**
     * SELCT * FROM Emp LEFT JOIN Dept
     */
    List<EmpDept> selectEmpJoinDept(EmpDept empDeptParam);
}



任意のMapperを利用したSQL発行

上記で作成したMapperは自動生成したMapperと同様の実装で利用できます。
    private static EmpDeptSqlMap empDeptSqlMap;

    public static void main(String[] args)  {
        // セッション作成
        SqlSession session = SessionUtil.createSession();
        // Mapperを取得
        empMapper = session.getMapper(EmpMapper.class);
        deptMapper = session.getMapper(DeptMapper.class);
        empDeptSqlMap = session.getMapper(EmpDeptSqlMap.class);

        try {
            // 手動作成したMapperを利用したSQLの発行
            EmpDept empDeptParam = new EmpDept();
            empDeptParam.setDeptName("%S%"); // dept.name Like '%S%'
            LOG.debug("【SQL発行】selectEmpJoinDept dept.name like '%S%' 】");
            List<EmpDept> empDeptList = empDeptSqlMap.selectEmpJoinDept(empDeptParam);
            printEmpDept(empDeptList);

        } finally {
            // 実行前の状態に戻す
            session.rollback();
            // セッションを閉じる
            session.close();
        }
    }

    /**
     * EmpDeptの中身をダンプする
     * @param empList
     */
    private static void printEmpDept(List<EmpDept> empDeptList) {
        for (EmpDept ed : empDeptList) {
            printEmpDept(ed);
        }
    }

    private static void printEmpDept(EmpDept empDept) {
        if (empDept != null) {
            LOG.debug("【Result】 " + "empId:" + String.valueOf(empDept.getEmpId())
                    + ", deptId:" + String.valueOf(empDept.getDeptId())
                    + ", empName:" + empDept.getEmpName()
                    + ", deptName:" + empDept.getDeptName()
                    + ", Tel:" + empDept.getTel());
        }
    }

実行すると以下の結果が得られます。
MyBatisSample - 【SQL発行】selectJoinDept dept.name like '%S%' 】
selectEmpJoinDept - ooo Using Connection [org.postgresql.jdbc4.Jdbc4Connection@2b4d13ef]
selectEmpJoinDept - ==>  Preparing: SELECT emp.id AS emp_id ,emp.dept_id AS dept_id ,dept.name AS dept_name ,emp.name AS emp_name ,emp.tel AS tel FROM my.emp emp LEFT JOIN my.dept dept ON emp.dept_id = dept.id WHERE dept.name LIKE ? ORDER BY emp.id 
selectEmpJoinDept - ==> Parameters: %S%(String)
selectEmpJoinDept - <==      Total: 2
MyBatisSample - 【Result】 empId:3, deptId:3, empName:Bravo, deptName:System, Tel:222-222-2222
MyBatisSample - 【Result】 empId:4, deptId:2, empName:Charlie, deptName:Sales, Tel:333-333-3333

Mapperファイル内には複数のSQLが記述可能なため、例えば親テーブル毎にMapperを分けるなどすれば管理もしやすくなると思います。


今回でひとまずMyBatisサンプルの動作まで確認できました
・・・が、Mapperを追加するたびに毎度設定ファイルを書き換えたり、セッション管理ロジックを書いたり、Mapperの取得したりするのはめんどくさいと思います。
MyBatisにはSpringFrameworkとシームレスに連携出来してセッションの生成、Mapperの注入などを自動で行うMyBatis-Springという拡張フレームワークが存在します。

この拡張フレームワークのおかげでMyBatisとSpringの連携は簡単に実装できるのでそちらの方がメインの使い方になると思いますが、今回はとりあえずMyBatisだけに絞りました。
MyBatis-Springの方の記事も時間があればいずれ書きたいと思います。

2014年3月22日土曜日

MyBatisで遊んでみる(2) 第二章 mybatis-generatorによるMapper自動生成

どうも、トムです。
今回は前回からの続きでmybatis-generatorについて書いていきます。

mybatis-generatorはmybatisで利用するMapperファイル(SQLMapper)やJava Model(Entity)、Java Client(Mapper)などのSQLマッピングクラスを自動生成してくれるツールです。
これらを導入することで開発時にテーブル変更などがあった際、比較的楽に関連ファイルを作成することが出来ます。

前回で以下のテーブルが出来ていることを前提で進んでいきます。
\d my.dept
            テーブル "my.dept"
  列  |           型           |  修飾語
------+------------------------+----------
 id   | integer                | not null
 name | character varying(256) | not null
インデックス:
    "dept_pkey" PRIMARY KEY, btree (id)
参照元:
    TABLE "my.emp" CONSTRAINT "emp_dept_id_fkey" FOREIGN KEY (dept_id) REFERENCES my.dept(id)

\d my.emp
              テーブル "my.emp"
   列    |           型           |  修飾語
---------+------------------------+----------
 id      | integer                | not null
 dept_id | integer                | not null
 name    | character varying(256) | not null
 tel     | character varying(12)  | not null
インデックス:
    "emp_pkey" PRIMARY KEY, btree (id, dept_id)
外部キー制約:
    "emp_dept_id_fkey" FOREIGN KEY (dept_id) REFERENCES my.dept(id)

第二章 mybatis-generatorによるMapper自動生成

1. モジュールダウンロード

まずは必要なモジュールをダウンロードします。
mybatis 3
https://github.com/mybatis/mybatis-3/releases
mybatis-3.2.5.jar
記事作成時点での最新バージョンは「mybatis 3.2.5」
mybatis-generator
https://github.com/mybatis/generator/releases
mybatis-generator-core-1.3.2.jar
※クラスパスには含めません
postgreSQL jdbcドライバ
http://jdbc.postgresql.org/download.html
postgresql-9.3-1101.jdbc41.jar
記事作成時点での最新バージョンは「9.3-1101」
対応するドライバの種類は以下の通りです。
JDKバージョン 対応ドライバ
JDK 1.5 JDBC3
JDK 1.6 JDBC4
JDK 1.7, 1.8 JDBC41

ognl-3.0.6.jar
http://struts.apache.org/download.cgi
javassist.jar
http://sourceforge.jp/projects/sfnet_jaopframework/downloads/Library/javassist.jar/
log4j-1.2.17.jar
http://www.apache.org/dyn/closer.cgi/logging/log4j/1.2.17/log4j-1.2.17.zip


2. パッケージ構成

今回作成するMyBatisサンプルのパッケージ構成は以下の通り

3. Mapper、Entity自動生成の為の準備

以下の設定ファイルを新規に作成します。

mybatis-generator用の設定ファイル

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE generatorConfiguration
 PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
 "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd" >
<generatorConfiguration>
  <context id="context1">
    <!--
      生成するクラスオブジェクトにタイムスタンプを付与するかどうかを設定します。
      value="true" の場合は生成しません。

      詳細は公式リファレンス参照
      http://mybatis.github.io/generator/configreference/commentGenerator.html
    -->
    <commentGenerator>
        <property name="suppressDate" value="true" />
    </commentGenerator>

    <!-- JDBCの設定 -->
    <jdbcConnection driverClass="org.postgresql.Driver"
                        connectionURL="jdbc:postgresql://192.168.100.100:5432/test" userId="mybatisuser"
                        password="password" />

    <!--
       Java Model(Entity)クラスの生成先を指定します。
       targetPackage : 生成先パッケージ
       targetProject : プロジェクトディレクトリから生成先パッケージの親ディレクトリまでのパス

       詳細は公式リファレンス参照
       http://mybatis.github.io/generator/configreference/javaModelGenerator.html
     -->
    <javaModelGenerator targetPackage="jp.hit.sample.mybatis.entity"
                        targetProject="src" >
    </javaModelGenerator>

    <!--
       SQL Mapperファイルの生成先を指定します。
       targetPackage : 生成先パッケージ
       targetProject : プロジェクトディレクトリから生成先パッケージの親ディレクトリまでのパス

       詳細は公式リファレンス参照
       http://mybatis.github.io/generator/configreference/sqlMapGenerator.html
     -->
    <sqlMapGenerator targetPackage="jp.hit.sample.mybatis.mapper"
                        targetProject="resource" />

    <!--
       Java Clientクラスの生成先を指定します。
       Java ClientはSQL Mapperファイルを呼び出すためのインターフェースクラスです。
       targetPackage : 生成先パッケージ
       targetProject : プロジェクトディレクトリから生成先パッケージの親ディレクトリまでのパス

       詳細は公式リファレンス参照
       http://mybatis.github.io/generator/configreference/javaClientGenerator.html

       type :
         type="ANNOTATEDMAPPER"
            アノテーションを定義したMapperインターフェースクラスとアノテーションの実装を定義したSqlProviderクラスを生成する。
            Mapperファイルは生成しない。
            Mapperファイルを使用せずにアノテーションでクエリを発行したい人向け

         type="MIXEDMAPPER"
            アノテーションを定義したMapperインターフェースクラスとMapperファイルを生成する。
            SqlProviderクラスは生成しない。
            Mapperファイルとアノテーションでのクエリ発行を両立したい人向け。

         type="XMLMAPPER"
            MapperインターフェースクラスとMapperファイルのみ生成する。
            SQLを全部Mapperファイルで管理したい人向け。
     -->
    <javaClientGenerator targetPackage="jp.hit.sample.mybatis.client"
                        targetProject="src" type="XMLMAPPER" />

    <!--
     自動生成対象のテーブル名を[tableName]に指定する。
     ※テーブル名の指定はワイルドカードが利用できます

     詳しい設定値については公式サイトのリファレンスを参照してください。
     http://mybatis.github.io/generator/configreference/table.html

     modelType :
       modelType="flat"
          ドメインクラスのみ作成。
       modelType="hierarchical"
          自動生成するMapperのパラメータの為にPrimary Keyエンティティを生成します。
          MapperでPKを指定したクエリ(selectByPrimaryKey等)のパラメータがデフォルトでPrimary Keyエンティティになります。
     -->
    <table schema="my" tableName="%"
            enableInsert="true"
            enableSelectByPrimaryKey="true"
            enableSelectByExample="true"
            enableUpdateByPrimaryKey="true"
            enableUpdateByExample="false"
            enableDeleteByPrimaryKey="true"
            enableDeleteByExample="false"
            enableCountByExample="false"
            selectByExampleQueryId="false"
            modelType="hierarchical">
    </table>
  </context>
</generatorConfiguration>

Antでmybatis-generatorを実行するためのビルドファイル

<?xml version="1.0" encoding="utf-8"?>
<project default="genfiles" basedir=".">
  <property name="generated.source.dir" value="${basedir}" />

  <path id="class.path">
    <fileset dir="lib" includes="*.jar" />
    <dirset dir="bin" />
  </path>

  <!-- 自動生成実行 -->
  <target name="genfiles" description="Generate the files" depends="init">
    <!-- mybatis generator 実行 -->
    <taskdef name="mbgenerator" classname="org.mybatis.generator.ant.GeneratorAntTask"
            classpathref="class.path" />
    <mbgenerator overwrite="true" configfile="resource/generatorConfig.xml"
            verbose="false">
    </mbgenerator>
    <!-- postgresの場合 PKオブジェクトとして[テーブル名Pkey]のファイルが作成されるが不要なため削除する -->
    <delete verbose="true">
      <fileset dir="./src/jp/hit/sample/mybatis/entity" includes="*Pkey.java"/>
      <fileset dir="./src/jp/hit/sample/mybatis/entity" includes="*PkeyExample.java"/>
      <fileset dir="./src/jp/hit/sample/mybatis/client" includes="*PkeyMapper.java"/>
      <fileset dir="./src/jp/hit/sample/mybatis/client" includes="*PkeySqlProvider.java"/>
      <fileset dir="./resource/jp/hit/sample/mybatis/mapper"  includes="*PkeyMapper.xml" />
    </delete>
  </target>

  <!-- 生成先パッケージ初期化 -->
  <target name="init" description="Initialize">
    <!-- パッケージ作成 -->
    <mkdir dir="./src/jp/hit/sample/mybatis/entity"/>
    <mkdir dir="./src/jp/hit/sample/mybatis/client"/>
    <mkdir dir="./resource/jp/hit/sample/mybatis/mapper"/>
    <!-- パッケージ内削除 ※全消しなので要注意 -->
    <delete verbose="true">
      <fileset dir="./src/jp/hit/sample/mybatis/entity" includes="*.java"/>
      <fileset dir="./src/jp/hit/sample/mybatis/client" includes="*.java"/>
      <fileset dir="./resource/jp/hit/sample/mybatis/mapper"  includes="*.xml" />
    </delete>
  </target>
</project>



4. 自動生成実行

Antでmybatis-generatorを実行します。
Buildfile: <workspace_path>\MyBatis\ant_mybatis-gemerator-build.xml
init:
genfiles:
BUILD SUCCESSFUL
Total time: 3 seconds


ここでエラーになる場合は、generatorConfig.xmlのJDBC設定やDBの設定周りを見直してみてください。
自動生成に成功すればパッケージ以下にMapperクラス、Entityクラス、Mapperが作成されます。


今回はMapperファイルを利用してのクエリ発行を行うのでJava Clientの設定値でtype="XMLMAPPER"を指定しました。
mybatisにはMapperファイルを利用したクエリ発行以外にもアノテーションを利用したクエリ発行の方法も可能です。
アノテーションを利用したクエリ発行のメリットは余計な外部ファイルを持たせずに全てclass内でクエリの定義が行えることでしょうか。
機会があればそちらの方法も試してみようと思います。