MyBatisを用いたMapping その１ #memo

#Mapper XMLファイル
Mapped StatementこそMyBatisの強みである。JDBCで同じ処理を書くのと比べると９割のコードが省略できるだろう。
Mapper XMLファイルの第一階層の要素は下記の通りである。（この順番で定義する必要がある）

* cache： 指定されたネームスペースに対するキャッシュの設定
* cache-ref： 別のネームスペースで定義されているキャッシュ設定を参照
* resultMap： DBから取得した結果セットをJavaオブジェクトにマッピングするための情報を記述する。最も複雑だが重要な要素。
* sql： 他のステートメントから参照することができる。再利用可能なSQL文字列。
* insert： マップされたINSERTステートメント。
* update： マップされたUPDATEステートメント。
* delete： マップされたDELETEステートメント。
* select： マップされたSELECTステートメント。

##select
selectステートメントは、MyBatisで最も頻繁に使われる要素の一つ。insert, update, deleteのそれぞれに対して、多くのselectがあるはずだ。これはMyBatisの大原則の一つであり、クエリ発行と結果のマッピングに注力している理由でもある。シンプルなケースでは、select要素は非常に簡単である。

```xml:sample.xml
<select id="selectPerson" parameterType="int" resultType="hashmap">
   SELECT * FROM PERSON WHERE ID = #{id}
</select>
```
これはselectPersonというステートメントで、int（またはInteger）型の引数を取り、列名をkey、値をvalueとして保持するHashMapを返す。

```
// Similar JDBC code, NOT MyBatis...
String selectPerson = "SELECT * FROM PERSON WHERE ID=?";
PreparedStatement ps = conn.preoareStatement(selectPerson);
ps.setInt(1,id);
```
JDBC単体でselect結果を展開してオブジェクトのインスタンスにマップするためにはもっと多くのコードが必要だが、MyBatisを使えばそうしたコードは書かずに済む。ステートメントに関しては細かい設定ができるように、select要素には多くの属性がある。

```xml
   id="selectPerson"
   parameterType="int"
   resultType="hashmap"
   resultMap="personalResultMap"
   flushCache="false"
   useCache="true"
   timeout="10"
   fetchSize="256"
   statementType="PREPARED"
   resultSetType="FORWARD_ONLY">
```
**Select Attributes**

| 属性 | 説明 |
|:-:|:-:|
| id  | このネームスペース内で固有な識別子。ステートメントを参照する際に使用  |
| parameterType | このステートメントに渡される引数の型。  |
| resultType  | このステートメントから返されるオブジェクトの型。  |
| resultMap  | 別の場所で定義されているresultMapを参照する。  |
| flushCache  | trueを指定した場合、ステートメント実行時にローカルキャッシュおよび２次キャッシュがフラッシュ（クリア）される。selectステートメントではデフォルト値```false```  |
| useCache  | trueを指定した場合、ステートメントの結果が２次キャッシュに保存される。  |
| timeout  | 例外を投げるまでの最大待機時間。  |
| fetchSize  | ドライバーが結果を返す際に内部的に使用するキャッシュのサイズ指定  |
| statementType　　　　　 　　　　　　　　　　　   | MyBatisがクエリを実行する際に使用するStatementの種類を指定。設定可能な値は```STATEMENT```,```PREPARED```,```CALLABLE```で、それぞれ```Statement```,```PreparedStatement```,```CallableStatement```が使用される。  |
| resultSetType  | ```FORWARD_ONLY```,```SCROLL_SENSITIVE```,```SCROLL_INSENSITIVE```,```DEFAULT```を指定。  |
| databaseId | databaseIdProviderが設定されている場合、MyBatisは定義されているステートメントの中でdatabaseId属性が指定されていないステートメントおよび現在の設定と一致するdatabaseId属性を持ったステートメントをロードする。  |
| resultOrdered  | この属性は結果がネストされたselectステートメントでのみ有効である。trueが設定された場合、MyBatisはクエリの結果が正しい順番にソートされているという前提でマッピングを実行する。  |
| resultSets | 複数のResultSetを利用する場合にのみ有効。ステートメントが返すResultSetにそれぞれ任意の名前を付けてリストアップする。名前はカンマで区切る。 |

##insert, update and delete
データを変更するステートメントであるinsert, update, deleteは非常によく似た実装となっている。

```xml
<insert
   id="insertAuthor"
   parameterType="domain.blog.Author"
   flushCache="true"
   statementType="PREPARED"
   keyProperty=""
   keyColumn=""
   userGeneratedKeys=""
   timeout="20">
<update
   id="updateAuthor"
   parameterType="domain.blog.Author"
   flushCache="true"
   statementType="PREPARED"
   timeout="20">
<delete
   id="deleteAuthor"
   parameterType="domain.blog.Author"
   flusjCache="true"
   statement="PREPARED"
   timeout="20">
```
**Insert, Update and Delete Attributes**

| Attributes |
|:-:|
| id  |
| parameterType  |
| flushCache  |
| timeout  |
| statementType  |
| useGeneratedKeys  |
| keyProperty  |
| keyColumn  |
| databaseId  |
以下、insert, update, deleteステートメントの例をいくつか挙げる。

```xml
<insert id="insertAuthor">
   insert into Author (id, username, password, email, bio)
   values (#{id}, #{username}, #{password}, #{email}, #{bio})
</insert>
<update id="updateAuthor">
   update Author set
      username = #{username},
      password = #{password},
      email = #{email},
      bio = #{bio},
   where id = #{id}
</update>
<delete id="deleteAuthor">
   delete from Author where id = #{id}
</delete>
```
前述のように、insertは自動生成されたキーを扱うため、追加の属性や子要素を持つことができるようになっている。
MySQLにおいては、単純にuseGeneratedKeysにtrueを設定し、keyPropertyでキーが格納されるプロパティを指定する。例えば、上記のAuthorテーブルでid列に自動生成が設定されていた場合、ステートメントは次のように書く。

```xml
<insert id="insertAuthor" useGeneratedKeys="true" KeyProperty="id">
   insert into Author (username, password, email, bio)
   values (#{username}, #{password}, #{email}, #{bio})
</insert>
```
##sql
この要素を使うと、再利用可能なSQLコードのスニペット（断片）を定義しておいて他のステートメントにインクルードすることができる。

```xml
   <sql id="userColumns"> ${alias}.id, ${alias}.username, ${alias}.
```
上記のSQLスニペットを他のステートメントにインクルードするには次のように記述する。

```xml
<select id="selectUsers" resultType="map">
   select
      <include refid="userColumns"><property name="alias" value="t1"/></include>,
      <include refid="userColumns"><property name="alias" value="t2"/></include>
   from some_table t1
   cross join some_table t2
</select>
```
呼び出し側のproperty要素で指定された値を、sql要素に内包されたinclude要素のrefid属性、やproperty要素のvalue属性として指定することも可能。

```xml
<sql id="sometable">
   ${prefix}Table
</sql>
<sql id="someinclude">
   from
      <include refid="${include_target}"/>
</sql>
<select id="select" resultType="map">
   select
      field1, field2, field3
   <include refid="someinclude">
      <property name="prefix" value="Some"/>
      <property name="include_target" value="sometable"/>
   </include>
</select>
```
##Parameters
これまでのステートメントの例では、すべて単純なパラメータを利用していた。

```xml
<select id="selectUsers" resultType="User">
   select id, username, password
   from users
   where id = #{id}
</select>
```
上記は、名前を指定してパラメータを参照する単純型の例だが、パラメータとして複合型を渡した場合はもう少し複雑である。

```xml
<insert id="insertUser" parameterType="User">
   insert into users (id, username, password)
   values (#{id}, #{username}, #{password})
</insert>
```