JavaEE7でMyBatisを利用する

↓の続きです。
http://qiita.com/RyoTa63292153/items/ec0eaf0bd0a5820c4be6

*****
### 依存ライブラリを追加

`build.gradle`の`dependencies`に`compile 'org.mybatis:mybatis:3.4.2'`を追加します。

*****
### 設定ファイルを追加

`src/main/resources/mybatis-config.xml`を作成します。

GlassFishに登録したJDBCリソースを利用するため、`dataSource`の`type`を`JNDI`に設定します。
`property`の`data_source`の値は、`glassfish-resources.xml`で設定している`jndi-name`です。

`transactionManager`の`type`を`MANAGED`に設定します。

```xml:mybatis-config.xml
<?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>
    <!--
    Glassfishに登録したJNDIリソースを利用する
    data_sourceの指定が必須
    -->
    <environments default="apple">
        <!-- apple -->
        <environment id="apple">
            <transactionManager type="MANAGED">
                <property name="closeConnection" value="false"/>
            </transactionManager>
            <dataSource type="JNDI">
                <property name="data_source" value="jdbc/apple_data_source"/>
            </dataSource>
        </environment>
        <!-- pineapple -->
        <environment id="pineapple">
            <transactionManager type="MANAGED">
                <property name="closeConnection" value="false"/>
            </transactionManager>
            <dataSource type="JNDI">
                <property name="data_source" value="jdbc/pineapple_data_source"/>
            </dataSource>
        </environment>
    </environments>
    <!-- Mapperの登録が必須 -->
    <mappers>
        <mapper class="sample.payara.mybatis.mapper.AppleMyBatisMapper"/>
        <mapper class="sample.payara.mybatis.mapper.AppleMyBatisXmlMapper"/>
        <mapper class="sample.payara.mybatis.mapper.PineappleMyBatisMapper"/>
    </mappers>
</configuration>
```

*****
### `SqlSession`を取得するためのBeanを作成

`SqlSession`のインスタンスを、SQLを実行する度に`SqlSessionFactory#openSession`して取得しないようにします。

`SqlSession`を利用するクラスでは、以下のようにインスタンスを取得することができます。

```java
@Inject
private SqlSession sqlSession;
```

```java:sample.payara.mybatis.provider.MyBatisSqlSessionProvidor
@Stateless
public class MyBatisSqlSessionProvidor {
    /*
     * SqlSessionFactoryのインスタンスをCDI経由でインジェクションする
     * 下記で宣言している`appleSessionFactory`と`pineappleSessionFactory`がCDIに登録するメソッド
     */
    @AppleDataSource
    @Inject
    private SqlSessionFactory appleSessionFactory;

    @PineappleDataSource
    @Inject
    private SqlSessionFactory pineappleSessionFactory;

    private SqlSessionFactory create(String environment) {
        try (InputStream stream = Resources.getResourceAsStream("mybatis-config.xml")) {
            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            return builder.build(stream, environment);
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    /*
     * SqlSessionFactoryのインスタンスをCDIに登録
     * DataSourceを複数利用しているため、`@AppleDataSource`と`@PineappleDataSource`というannotationで識別している
     * `SqlSessionFactory`はアプリケーションが起動している間はインスタンスを破棄しないために`@ApplicationScoped`を指定する
     */
    @ApplicationScoped
    @AppleDataSource
    @Produces
    public SqlSessionFactory appleSessionFactory() {
        return this.create("apple");
    }

    @ApplicationScoped
    @PineappleDataSource
    @Produces
    public SqlSessionFactory pineappleSessionFactory() {
        return this.create("pineapple");
    }

    /*
     * `SqlSession`をインジェクションするためのメソッド
     * Request毎にopen/closeするため`@RequestScoped`を指定
     * `@Produces`でCDI経由でインスタンスを取得できるようになる
     */
    @RequestScoped
    @AppleDataSource
    @Produces
    public SqlSession appleSession() {
        return appleSessionFactory.openSession();
    }

    @RequestScoped
    @PineappleDataSource
    @Produces
    public SqlSession pineappleSession() {
        return pineappleSessionFactory.openSession();
    }

    /*
     * Requestが完了したときに`SqlSession`をcloseする
     */
    public void closeAppleSession(@Disposes @AppleDataSource SqlSession sqlSession) {
        sqlSession.close();
    }

    public void closePineappleSession(@Disposes @PineappleDataSource SqlSession sqlSession) {
        sqlSession.close();
    }
}
```

*****
### Mapperを作成

JavaAPIを利用したMapper

```java:sample.payara.mybatis.mapper.AppleMyBatisMapper
public interface AppleMyBatisMapper {

    /* SQL実行結果をオブジェクトにマッピングするための設定 */
    @Results(id = "findAllMybatisUser", value = {
            @Result(property = "id", column = "id", id = true),
            @Result(property = "name", column = "name"),
            @Result(property = "created", column = "created"),
            @Result(property = "updated", column = "updated"),
    })
    /* select文 */
    @Select({
        "select *",
        "from sample_model",
    })
    public List<MyBatisUser> findAll();

    @Results(id = "findByMybatisUser", value = {
            @Result(property = "id", column = "id", id = true),
            @Result(property = "name", column = "name"),
            @Result(property = "created", column = "created"),
            @Result(property = "updated", column = "updated"),
    })
    @Select({
        "select *",
        "from sample_model s",
        "where s.id = #{id}"
    })
    public MyBatisUser findById(@Param("id") Long id);

    /* SQL文を動的に組み立てる */
    @SelectProvider(type = MyBatisMapperSqlBuilder.class, method = "findByParamSql")
    public List<MyBatisUser> findByParam(@Param("param") MyBatisUserSearchParam param);
}
```

```java:sample.payara.mybatis.mapper.MyBatisMapperSqlBuilder
public class MyBatisMapperSqlBuilder {
    /*
     * SQL文の`#{param.xxx}`の部分は、このメソッドの`@Param("param")`を参照している
     * `AppleMyBatisMapper#findByParam`で指定されている`param`では無い
     */
    public String findByParamSql(@Param("param") final MyBatisUserSearchParam param) {
        SQL sql = new SQL()
                .SELECT("*")
                .FROM("sample_model s");

        if (param.hasId()) {
            sql.WHERE("s.id = #{param.id}");
        }

        if (param.hasName()) {
            sql.WHERE("s.name like #{param.name} ");
        }

        return sql.toString();
    }

}
```

XMLを利用したMapper

```java:sample.payara.mybatis.mapper.AppleMyBatisXmlMapper
public interface AppleMyBatisXmlMapper {

    public MyBatisUser findById(@Param("id") final Long id);

    public List<MyBatisUser> findByParam(@Param("param") final MyBatisUserSearchParam param);

}
```

```xml:src/main/java/sample/payara/mybatis/mapper/AppleMyBatisXmlMapper.xml
<?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="sample.payara.mybatis.mapper.AppleMyBatisXmlMapper">
    <resultMap type="sample.payara.model.MyBatisUser" id="MyBatisUser">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="created" property="created"/>
        <result column="updated" property="updated"/>
    </resultMap>
    <select id="findById" resultMap="MyBatisUser">
        SELECT *
          FROM sample_model s
        <where>
            AND s.id = #{id}
        </where>
    </select>
    <select id="findByParam" resultMap="MyBatisUser">
        SELECT *
          FROM sample_model s
        <where>
            <if test="param.hasId()">
                AND s.id = #{param.id}
            </if>
            <if test="param.hasName()">
                <bind name="pattern" value="param.name + '%'"/>
                AND s.name LIKE #{pattern}
            </if>
        </where>
    </select>
</mapper>
```

*****
### Mapperを呼び出す

`SqlSession`からMapperのインスタンスを取得してメソッドを実行できます。

```java:sample.payara.mybatis.repotiroy.AppleMyBatisRepository
@Stateless
public class AppleMyBatisRepository {
    @AppleDataSource
    @Inject
    private SqlSession sqlSession;

    /*
     * `sqlSession.getMapper`でMapperのインスタンスを取得できる
     */
    private AppleMyBatisMapper mapper() {
        return sqlSession.getMapper(AppleMyBatisMapper.class);
    }

    private AppleMyBatisXmlMapper xmlMapper() {
        return sqlSession.getMapper(AppleMyBatisXmlMapper.class);
    }

    public List<MyBatisUser> findAll() {
        return mapper().findAll();
    }

    public MyBatisUser findBy(final Long id) {
        return mapper().findById(id);
    }

    public List<MyBatisUser> findBy(final MyBatisUserSearchParam param) {
        return mapper().findByParam(param);
    }

    public List<MyBatisUser> findByXmlMapper(final MyBatisUserSearchParam param) {
        return xmlMapper().findByParam(param);
    }
}
```

*****
### 参考

参考にしました m(\__)m

http://n-agetsuma.hatenablog.com/entry/2013/01/13/151303
http://qiita.com/opengl-8080/items/431de9175dca33a09ba8
http://www.mybatis.org/mybatis-3/ja/index.html

ソースは↓にあります、参考になれば幸いです
https://github.com/yamashiro0110/JavaEE/tree/master/Payara