Javaでデータベースを扱うとき、選択肢が多くて迷います。
- なるべく早く作りたい
- パフォーマンスも気になる
- 既存の複雑なテーブルに合わせないといけない
- SQLをしっかり管理したい
- でも、安全性は絶対に落としたくない
こういう現場の悩みに、ちょうどハマりやすいのが MyBatis です。
MyBatisは一言でいうと、
「SQLを自分で書きつつ、JDBCの面倒をほぼ消して、Javaの型にきれいに戻してくれる仕組み」。
そして、ここが本題です。
JavaとMyBatisは相性がいい。
理由は「便利だから」ではなく、Javaの設計思想(責務分離、型、安全な実装)と、MyBatisのSQL主導がピタッと噛み合うからです。
この記事では、初心者でも腹落ちするように、ゆっくり解説します。
- MyBatisが向く場面
- JPAとの考え方の違い
- Spring / Spring Bootと組み合わせたときの強み
- 事故りやすいポイント(特に
${}) - チーム開発で安全に運用するコツ
- MyBatisは「SQLを捨てない」選択
- JavaとMyBatisが相性いい理由
- 最小構成でイメージするMyBatis
- 実装例:サービスとMapperのきれいな分離
- 実装例:SQLを外に出す(XMLのイメージ)
- ここが最重要:#{} と ${} の違い
- ${} を使いたくなる場面と、安全な考え方
- 動的SQLは強い。だからこそ「型」を作る
- MyBatisとJPAの違いは「設計の主役」が違う
- Spring / Spring Bootと合わせると強くなる理由
- よくある「つまずき」と回避策
- チーム開発でのMyBatis運用ルール
- レビューで使えるチェックリスト
- まとめ:JavaとMyBatisは「設計」と「SQL」が噛み合う
- 絶対にJavaプログラマーになりたい人へ
MyBatisは「SQLを捨てない」選択
JavaのDBアクセスというと、最初にこういう印象を持つ人が多いです。
- ORMは便利そう
- SQLはなるべく書かないほうがよさそう
でも現場には、SQLを避けられない理由が普通にあります。
- 集計や結合が多い
- 既存DBの都合でテーブル設計が複雑
- 実行計画やインデックスを見ながら調整したい
- SQLが仕様そのもの(レビュー対象)
こういうとき、「SQLは書かない」よりも
**「SQLを安全に、読みやすく、管理できる」**ことが大事になります。
MyBatisは、そこに強いです。
JavaとMyBatisが相性いい理由
相性の良さは、ふわっとした話ではありません。理由があります。
Javaの強みは「境界をきれいに作れる」こと
Javaは、インターフェースや型で、役割をはっきり分けるのが得意です。
- どこからどこまでがDBアクセスか
- どこからが業務ロジックか
- 何を入力して何を返すか
これがコードとして見えます。
MyBatisも、まさにその形に合います。
Mapperという境界が作れるからです。
MyBatisの強みは「SQLの責務を外に出せる」こと
SQLをサービスの中にべったり書くと、こうなります。
- ロジックとSQLが混ざる
- テストしづらい
- 変更の影響が読めない
MyBatisは、SQLをMapper側に寄せて、Java側の責務を軽くできます。
結果として、「Javaらしい設計(読みやすい、直しやすい)」になります。
最小構成でイメージするMyBatis
「結局、何がどうなるの?」をイメージするために、最小の形を見ます。
役割の分担
- サービス層:業務の流れをまとめる
- Mapper:DBに何を聞くかを定義する
- SQL(XMLなど):実際の問い合わせを書く
この分割が、Javaの得意な「責務分離」と一致します。
実装例:サービスとMapperのきれいな分離
サービス層の例(依存注入でスッキリ)
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class UserService {
private final UserMapper userMapper;
public UserService(UserMapper userMapper) {
this.userMapper = userMapper;
}
@Transactional
public UserDto findUser(UserId id) {
return userMapper.selectUser(id);
}
}
ここで見てほしいのは、サービスがやっているのは「流れ」であって、SQLの詳細ではない点です。
読み手が安心する構造です。
Mapperインターフェースの例
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserMapper {
UserDto selectUser(UserId id);
}
これだけ見ると、「SQLはどこ?」となりますよね。
SQLは、XML側に置く形がよく使われます。
実装例:SQLを外に出す(XMLのイメージ)
<mapper namespace="com.example.UserMapper">
<select id="selectUser" parameterType="com.example.UserId" resultType="com.example.UserDto">
SELECT
user_id,
user_name
FROM
users
WHERE
user_id = #{value}
</select>
</mapper>
ここで注目ポイントは #{} です。
この #{} は、MyBatisを安全に使う上で超重要です。
ここが最重要:#{} と ${} の違い
MyBatisで事故が起きるとしたら、だいたいここです。
#{} は「値」として渡す
#{} は、SQLの中で 値 として扱われやすい書き方です。
安全に使いやすいのはこちらです。
${} は「文字列として差し込む」
${} は、文字をそのままSQLに差し込むような形になりやすいです。
つまり、入力を間違えると SQLインジェクションに直結します。
ここは強く言います。
基本は #{}。${} は「分かっていて、必要なときだけ」です。
${} を使いたくなる場面と、安全な考え方
とはいえ現場では、こういう要望が出ます。
- 並び順を選べる検索にしたい
- 検索対象のカラムを切り替えたい
このとき、値として渡せないもの(カラム名や並び順)は、つい ${} を使いたくなります。
でも、ここで「ユーザー入力をそのまま ${}」は危険です。
安全にする基本は「ホワイトリスト」
つまり、使ってよい候補を サーバ側で決め打ちします。
例として、並び順を「決められた候補だけ」にします。
- 名前順
- 作成日時順
- 更新日時順
そして、その候補をJava側で選ばせます。
「自由入力」にしないのがコツです。
動的SQLは強い。だからこそ「型」を作る
MyBatisの強みのひとつが動的SQLです。
検索条件が増えたり、条件でWHERE句が変わったりする場面で便利です。
でも、便利すぎてこうなりがちです。
- 条件分岐が増えすぎる
- SQLが読みにくくなる
- 仕様変更のたびに怖くなる
ここでJavaの出番です。
条件を「まとまり」として表現する
検索条件をバラバラの引数で渡すのではなく、条件用のクラスにまとめます。
- 入力が増えても拡張しやすい
- バリデーションしやすい
- SQL側も読みやすい
この「型を作って守る」考え方は、まさにJavaが得意です。
MyBatisとJPAの違いは「設計の主役」が違う
対立ではなく、得意分野が違います。
- JPA:オブジェクト中心に設計しやすい。CRUDに強い
- MyBatis:SQL中心に設計しやすい。複雑クエリに強い
ここで大事なのは「どっちが上」ではなく、要件とチームの勝ち筋に合うかです。
比較表(文字だけで整理)
| 観点 | MyBatis | JPA |
|---|---|---|
| 主役 | SQL | オブジェクト |
| 強い場面 | 複雑な検索、集計、既存DB | CRUD中心、ドメイン設計 |
| 読み方 | SQLレビューがしやすい | モデル設計が効く |
| 注意点 | ${} と動的SQLの暴走 | 取得戦略や発行SQLの見えにくさ |
Spring / Spring Bootと合わせると強くなる理由
MyBatis単体でも便利ですが、Springと合わせるとさらに強くなります。
- 依存注入でMapperをきれいに扱える
- トランザクション管理をSpringに寄せられる
- サービス層が読みやすくなる
- テストがしやすくなる
つまり、MyBatisのSQL力を、Springの設計力で安全に包むイメージです。
よくある「つまずき」と回避策
つまずき:Mapperが肥大化する
SQLを全部Mapperに集めると、Mapperが巨大になりがちです。
回避策はシンプルです。
- 「用途ごと」にMapperを分ける
- ひとつのSQLの責務を小さく保つ
- 名前で意図が伝わるようにする
つまずき:いわゆるエヌプラスワン問題
取得の仕方によって、DBアクセスが増えすぎることがあります。
これはMyBatisでも起きます。
回避策は、レビューの観点を持つことです。
- 「この処理、何回DBに行く?」を意識する
- SQLを一度で取れる形に寄せる
- まとめて取る設計を優先する
つまずき:動的SQLが読めなくなる
動的SQLは便利ですが、分岐が増えると地獄になります。
回避策は、
- 条件クラスを作る
- SQLの分岐を増やしすぎない
- 「分岐の型」をチームで統一する
です。
チーム開発でのMyBatis運用ルール
MyBatisは「SQLが書ける人だけが強い」と言われることがあります。
でもそれは、ルールがないチームで起きやすい話です。
ルールがあると、MyBatisはチーム全体の武器になります。
ルール例(すぐ効くもの)
- パラメータは基本
#{}にする ${}を見つけたら「安全な根拠」を必ず説明する- SQLの命名規則を決める
- Mapperの責務範囲を決める
- 大きすぎるSQLは分割や見直しを検討する
レビューで使えるチェックリスト
最後に、レビューでそのまま使える形にまとめます。
- 入力が入る場所は
#{}になっているか ${}を使っているなら、候補が固定されているか(自由入力ではないか)- SQLの責務が大きすぎないか(読める大きさか)
- Mapperとサービスの責務が混ざっていないか
- DBアクセス回数が増えすぎる形になっていないか
この視点があるだけで、MyBatisはかなり安全に運用できます。
まとめ:JavaとMyBatisは「設計」と「SQL」が噛み合う
JavaとMyBatisの相性がいい理由を、もう一度まとめます。
- Javaは責務分離と型で、設計を守れる
- MyBatisはSQLを明示でき、現場の要件に強い
- Springと組み合わせると、管理と安全性が上がる
- 最大の注意点は
${}。ここを制御できれば強い
つまり、MyBatisは「雑に使うと危ない」。
でも「理解して使うと、とても強い」。
そしてJavaは、その「理解して安全に使う」ための土台が強い言語です。
絶対にJavaプログラマーになりたい人へ
MyBatisを使いこなす力は、単なるSQL力ではありません。
設計力、レビュー力、安全性の意識がセットで問われます。
もしあなたが、
- Javaで仕事がしたい
- DBアクセスで評価されたい
- 安全で読みやすい設計を身につけたい
と思うなら、まずは自己学習の軸を固めましょう。
おすすめはこちらです。
絶対にJavaプログラマーになりたい人へ。
https://amzn.asia/d/3E1CYbv
それでも、
- 自分のSQLやMapper設計が正しいか不安
- コードレビューをしてほしい
- 転職も含めてサポートが欲しい
という方は、こちらも検討してみてください。
サイゼントアカデミー
https://academy.cyzennt.co.jp
自己学習で身につけた力を、現場で通用する形に整える場所としておすすめです。

コメント