MyBatisを学び始めると、最初に少し戸惑いやすいのがMapper XMLです。
Javaのコードを書いているのに、SQLはXMLファイルに書く。しかも、Mapperインターフェースとひも付いて動く。この流れが最初は少しわかりにくく感じます。
ただ、ここが理解できると、MyBatisはかなり読みやすくなります。
特に、SQLを自分で書きたい人にとっては、JPAのように自動生成に寄せるよりも、何が実行されるかを追いやすいのが大きな特徴です。
この記事では、Mapper XMLを初めて見る人向けに、何を書くファイルなのか、どうやってJavaとつながるのか、まずどこまで理解すればよいのかをやさしく整理していきます。
MyBatisのMapper XMLの基本
ここでは、Mapper XMLがどんな役割を持つのかを説明します。
Mapper XMLは何を書くファイルなのか
Mapper XMLは、SQLを書くためのファイルです。
MyBatisでは、データベースに対して実行したい select、insert、update、delete などのSQLを、このXMLに定義します。
つまり、Mapper XMLは単なる設定ファイルというより、SQLを管理する場所と考えたほうがわかりやすいです。
たとえば、ユーザー一覧を取得するSQLなら、次のように書きます。
<select id="findAll" resultType="User">
SELECT
id,
name,
email
FROM users
</select>この例では、findAll という名前のSQLが定義されています。SELECT 文の結果を User にマッピングして返す、という意味です。
最初はXMLという見た目に少し身構えますが、やっていることはそこまで複雑ではありません。
**「このメソッドが呼ばれたら、このSQLを実行する」**という対応関係を作っているだけです。
Mapperインターフェースとどうつながるのか
Mapper XMLは、JavaのMapperインターフェースとセットで使います。
たとえば、次のようなインターフェースがあるとします。
public interface UserMapper {
List<User> findAll();
}これに対応するMapper XMLで、同じ名前のSQLを定義します。
<mapper namespace="com.example.mapper.UserMapper">
<select id="findAll" resultType="User">
SELECT
id,
name,
email
FROM users
</select>
</mapper>ここで大事なのは、次の2点です。
namespaceは Mapperインターフェースの完全修飾名に合わせるidは メソッド名に合わせる
つまり、この例では
namespace="com.example.mapper.UserMapper"id="findAll"
という組み合わせによって、UserMapper#findAll() とXMLの select が結び付いています。
最初は少し機械的に見えるかもしれませんが、慣れるとかなり素直です。
インターフェースが呼び出し口で、XMLがSQL本体というイメージを持つと整理しやすくなります。
XMLでSQLを書くメリット
最近はアノテーションでSQLを書く方法もありますが、MyBatisではXMLがよく使われます。
理由は、SQLが長くなったときにXMLのほうが整理しやすいからです。
たとえば、簡単なSQLならアノテーションでも書けます。
@Select("""
SELECT id, name, email
FROM users
WHERE id = #{id}
""")
User findById(Long id);ただ、条件が増えたり、JOINが入ったり、動的SQLが必要になったりすると、アノテーションではかなり読みにくくなります。
その点、XMLなら
- SQLをまとまった形で見やすい
- 複雑なSQLでも整形しやすい
- 動的SQLと相性がよい
という強みがあります。
特にMyBatisは、SQLを自分でコントロールしたいときに強い仕組みです。
そのため、XMLでSQLを分けて管理するスタイルはかなり理にかなっています。
まず覚えたい基本の書き方
ここでは、初学者がまず押さえたい基本の書き方を説明します。
selectの基本
一番最初に覚えるのは select です。
データ取得の基本になるので、ここを読めるようになるだけでもかなり前進です。
<select id="findById" parameterType="long" resultType="User">
SELECT
id,
name,
email
FROM users
WHERE id = #{id}
</select>このSQLでは、id をもとに1件のユーザーを取得しています。
それぞれの意味は次の通りです。
id
Mapperインターフェースのメソッド名に対応するparameterType
引数の型を表すresultType
SQL結果をどの型で受け取るかを表す#{id}
メソッド引数の値をSQLに埋め込む
ここで特に大事なのは、#{} を使って値を受け取ることです。
MyBatisでは、プレースホルダのような感覚で使えます。
たとえば、次のようなMapperインターフェースに対応します。
public interface UserMapper {
User findById(Long id);
}この対応が見えるようになると、Mapper XMLの読み方が一気に楽になります。
insert / update / deleteの基本
取得だけでなく、登録、更新、削除も同じ考え方で書けます。
まずは insert の例です。
<insert id="insertUser" parameterType="User">
INSERT INTO users (
name,
email
) VALUES (
#{name},
#{email}
)
</insert>parameterType="User" としているので、User オブジェクトの name と email をそのまま使えます。
更新は次のようになります。
<update id="updateUser" parameterType="User">
UPDATE users
SET
name = #{name},
email = #{email}
WHERE id = #{id}
</update>削除はさらにシンプルです。
<delete id="deleteById" parameterType="long">
DELETE FROM users
WHERE id = #{id}
</delete>ここで大事なのは、select だけ特別なのではなく、どのSQLも基本構造は同じということです。
idでメソッドと対応する- 必要なら
parameterTypeを指定する - SQL本体を書く
#{}で値を受け取る
最初はこの流れだけ押さえれば十分です。
パラメータと検索結果の扱い方
Mapper XMLで最初に混乱しやすいのが、入力と出力をどう考えるかです。
かなり単純化すると、次の整理で大丈夫です。
- 入力側
parameterTypeや#{}で扱う - 出力側
resultTypeやresultMapで扱う
まず、入力の例です。
<select id="findByEmail" parameterType="string" resultType="User">
SELECT
id,
name,
email
FROM users
WHERE email = #{email}
</select>この場合、文字列のメールアドレスを受け取り、その値を #{email} で使っています。
次に、出力の例です。
<select id="findAll" resultType="User">
SELECT
id,
name,
email
FROM users
</select>この場合は、取得した各行を User に詰めて返します。
初学者のうちは、まず
入力は #{} で受け取る
出力は resultType で受け取る
という理解で十分です。
resultMap のような少し踏み込んだ機能は、必要になったときに覚えれば大丈夫です。
初学者がつまずきやすいポイント
ここでは、最初につまずきやすいポイントを整理します。
idとメソッド名の対応
MyBatisで最初に起きやすいミスの1つが、XMLの id とメソッド名が合っていないことです。
たとえば、インターフェースがこうだったとします。
public interface UserMapper {
User findById(Long id);
}このとき、XML側がこうなっていると合いません。
<select id="getById" parameterType="long" resultType="User">
SELECT
id,
name,
email
FROM users
WHERE id = #{id}
</select>メソッド名は findById なのに、XML側は getById になっています。
これでは正しく結び付かず、実行時エラーの原因になります。
最初のうちは、namespace と id は特に丁寧に確認するのが大事です。
MyBatisは自由度が高い分、ここがずれると素直に失敗します。
resultTypeとresultMapの違い
ここも初学者が迷いやすいところです。
まずはざっくり、次の理解で十分です。
resultType
カラム名とJavaのプロパティ名が素直に対応するときに使うresultMap
そのままでは対応できないときに使う
たとえば、テーブルのカラムが id、name、email のように、そのままJavaオブジェクトのプロパティへ対応するなら resultType で問題ありません。
<select id="findAll" resultType="User">
SELECT
id,
name,
email
FROM users
</select>一方で、カラム名とプロパティ名がずれるときは resultMap が必要になることがあります。
<resultMap id="userResultMap" type="User">
<id property="id" column="user_id"/>
<result property="name" column="user_name"/>
<result property="email" column="email_address"/>
</resultMap><select id="findAll" resultMap="userResultMap">
SELECT
user_id,
user_name,
email_address
FROM users
</select>ただ、初学者の段階では resultMap を深く掘りすぎなくて大丈夫です。
まずは、簡単な取得は resultType で書けると覚えておけば十分です。
最初はどこまで理解すれば十分か
MyBatisは学ぼうと思えばかなり広いです。
たとえば、次のような機能があります。
- 動的SQL
- resultMapの詳細な設定
- 関連オブジェクトのマッピング
- SQLフラグメントの再利用
- キャッシュ設定
ただ、最初から全部を理解しようとすると重くなります。
むしろ、入口では次の3つができれば十分です。
- MapperインターフェースとXMLの対応がわかる
select / insert / update / deleteの基本が読める#{}とresultTypeの役割がなんとなくわかる
ここまで理解できれば、もうMyBatisの基礎はかなりできています。
その後で、
- 条件付き検索が必要になったら動的SQL
- カラム名とプロパティ名がずれたらresultMap
- JOIN結果を丁寧に扱いたくなったらマッピングの応用
という順番で広げていけば十分です。
最初から全部理解しなくていいと思えるだけでも、かなり気が楽になるはずです。
まとめ
MyBatisのMapper XMLは、JavaのメソッドとSQLを結び付けるための場所です。
最初はXMLという見た目に少し構えやすいですが、整理するとやっていることはそこまで難しくありません。
まず押さえたいポイントは次の通りです。
- Mapper XMLはSQLを書くファイル
namespaceは Mapperインターフェースに合わせるidは メソッド名に合わせるselect / insert / update / deleteの基本形は似ている- 入力は
#{}、出力はresultTypeから覚えればよい
初学者のうちは、まずCRUDの基本を読めるようになることが大切です。
動的SQLや複雑なマッピングは、そのあとで十分です。
MyBatisは、SQLを自分で書きながらアプリときれいにつなげられるのが魅力です。
Mapper XMLの基本がわかると、その良さがかなり見えてきます。


コメント