Javaでデータベースを扱う場合、よく出てくるのがMyBatisとJPAです。
どちらも実務で広く使われていますが、実際に触ってみると「思っていたより全然違う」と感じることが多いです。
開発を進めるほど、SQLの書き方、コードの見え方、保守のしやすさ、チームとの相性まで大きく差が出てきます。
そのため、なんとなく選んでしまうと、あとから後悔しやすいテーマでもあります。
MyBatisとJPAの違い
ここでは、まず2つの考え方の違いを整理します。
細かい機能差を見る前に土台を押さえておくと、その後の比較がかなり理解しやすくなります。
MyBatisはSQLを直接書く
MyBatisは、SQLを自分で書いて、その結果をJavaオブジェクトにマッピングする考え方のフレームワークです。
たとえば、ユーザー一覧を取得したい場合は、SQLを明示的に記述します。
@Mapper
public interface UserMapper {
@Select("""
SELECT id, name, email
FROM users
WHERE status = #{status}
ORDER BY id DESC
""")
List<User> findByStatus(String status);
}この形のわかりやすさは、やはり大きいです。
実際にどんなSQLが実行されるのかがコードから見えるため、SQLを主体に考えたい人には扱いやすく感じられます。
また、JOINや集計、動的条件のようなクエリも、自分で意図した通りに組みやすいです。
その反面、SQLを書く量は増えやすく、テーブルやカラム変更の影響をコード側で追いかける必要もあります。
JPAはエンティティを中心に扱う
JPAは、データベースの表をオブジェクトとして扱い、その状態を永続化する考え方です。
SQLを書くこと自体が主役ではなく、エンティティをどう操作するかが中心になります。
たとえば、次のようにエンティティを定義します。
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
private String status;
// getter / setter は省略
}Repositoryでは、基本的なCRUDであればSQLを書かずに扱えます。
public interface UserRepository extends JpaRepository<User, Long> { // メソッド名からクエリを生成する
List<User> findByStatusOrderByIdDesc(String status);
}この形のよさは、定型的なデータ操作をかなり少ない記述量で書けることです。
一覧取得、詳細取得、保存、削除のような処理は、Spring Data JPAと組み合わせるとかなりスムーズに実装できます。
ただし、SQLが見えにくくなりやすく、内部でどういうクエリが発行されるのかを意識しないまま使うと、
思わぬ性能問題につながることがあります。
MyBatisとJPAの考え方の違い
MyBatisとJPAの違いを一言でまとめるなら、SQL中心で考えるか、オブジェクト中心で考えるかです。
MyBatisでは、まず「どんなSQLを流すか」を考えます。
そのSQL結果を、Javaのクラスにどう受け取るかを決めます。
一方でJPAでは、まず「どんなエンティティを扱うか」を考えます。
そのエンティティを保存・取得するための仕組みとしてDBアクセスが存在します。
この違いは、書き味だけでなく設計の視点にも影響します。
MyBatisは、DBの構造やSQLの意図を明示しやすいです。
JPAは、ドメインモデルを軸にアプリケーションを組み立てやすいです。
単純に「新しいからJPA」「SQLが好きだからMyBatis」と決めるのではなく、
自分たちの開発で何を重視するかを見る必要があります。
MyBatisとJPAを比較する
ここでは、実務でよく比較されるポイントごとに違いを整理します。
使ってみると見えてくる差は多いですが、まずは判断軸として使いやすいものに絞って見ていきます。
SQLの自由度
SQLの自由度は、MyBatisの方が明らかに高いです。
MyBatisは自分でSQLを書くので、複雑なJOIN、サブクエリ、ウィンドウ関数、
DB製品固有の構文なども、そのまま扱えます。
「このSQLをこの形で実行したい」が先にあるなら、かなり素直に書けます。
たとえば、検索条件が可変な場合も、動的SQLで組み立てられます。
<select id="searchUsers" resultType="com.example.User">
SELECT id, name, email, status
FROM users
<where>
<if test="name != null and name != ''">
AND name LIKE CONCAT('%', #{name}, '%')
</if>
<if test="status != null and status != ''">
AND status = #{status}
</if>
</where>
ORDER BY id DESC
</select>JPAでもJPQLやCriteria API、ネイティブクエリを使えば複雑なことはできます。
ただ、複雑なSQLになるほど、JPA本来の「少ない記述量で扱える」という良さは薄れやすいです。
SQLを細かく制御したいならMyBatisの方が自然です。
逆に、単純なCRUDが中心なら、JPAはSQLを書かずに進められる場面が多くなります。
記述量と保守性
定型的な処理に限れば、JPAの方が記述量は少なくなりやすいです。
たとえば、1件取得、保存、削除といった基本操作は、Repositoryを定義するだけでかなり整います。
public interface UserRepository extends JpaRepository<User, Long> {
}これだけで、findById、save、deleteById などの基本操作が使えます。
この生産性はかなり強力で、特に管理画面や業務系アプリのようにCRUDが多い場面では効いてきます。
一方のMyBatisは、必要なSQLを自分で書くぶん、初期の記述量は増えます。
ただし、その分だけ何をしているコードなのかが読み取りやすいという面もあります。
保守性については、一概にどちらが上とは言い切れません。
JPAはコード量を減らしやすいですが、内部の挙動を理解していないと、
あとから見たときに意図がつかみにくいことがあります。
MyBatisはSQLが見えるので追いやすいですが、クエリ数が増えると管理対象も増えます。
保守性はツール単体の優劣というより、チームがその仕組みをどれだけ理解しているかで大きく変わります。
学習コスト
最初の理解しやすさは、MyBatisの方が高いと感じる人が多いです。
理由は単純で、やっていることが見えやすいからです。
SQLを書いて、結果を受け取る。この流れは比較的直感的です。
SQL経験がある人なら、入り口で大きく迷いにくいでしょう。
JPAは便利ですが、便利なぶん見えにくい概念も増えます。
エンティティ、永続化コンテキスト、フェッチ戦略、遅延読み込み、カスケード、N+1問題など、
理解しておきたい前提知識がそれなりにあります。
もちろん、簡単なCRUDだけならJPAもすぐ使えます。
ただ、安全に使いこなすところまで含めると、JPAの方が学ぶことは多いです。
ここでよくあるのが、「JPAは楽そうだから採用したのに、後から挙動がわからなくて苦しくなる」という流れです。
JPA自体が悪いわけではなく、便利さの裏にある仕組みを理解せずに使うと困る場合が出てきます。

複雑なクエリへの向き不向き
複雑な検索や集計が多いなら、MyBatisの方が向いている場面は多いです。
たとえば、次のようなケースです。
- JOINが多い
- 集計やランキングがある
- 条件分岐が多い検索画面がある
- DB依存の最適化を行いたい
- 実行されるSQLを明示的に管理したい
こうした処理では、JPAでも実現はできますが、JPQLやCriteria APIが読みにくくなったり、
最終的にネイティブクエリに寄ったりしやすいです。
そこまで行くと、「JPAの恩恵を受けながら複雑なSQLもきれいに管理する」のが難しくなってきます。
一方で、会員登録、商品管理、基本的な更新処理のような素直なCRUD中心の開発では、
JPAの生産性がかなり活きます。
無理に全部をMyBatisで書くより、JPAの方がスムーズに進むことも多いです。
ここは優劣というより、得意分野の違いとして見るのが自然です。
MyBatisとJPAの選び方
MyBatisが向いている場合
MyBatisが向いているのは、SQLを資産として明示的に管理したい開発です。
特に相性がよいのは、次のようなケースです。
- 複雑な検索条件が多い
- JOINや集計が多い
- 既存DBに合わせる必要がある
- SQLチューニングをしながら開発したい
- 発行されるクエリを明確に把握したい
たとえば、業務システムでは「画面ごとにかなり細かい検索条件がある」
「一覧とCSV出力で微妙に条件が違う」「既存テーブル設計に制約が多い」といったことが珍しくありません。
こういう場面では、SQLを自分で持てるMyBatisの安心感が強いです。
また、DBAやSQLに強いメンバーがいるチームでは、MyBatisの方がレビューしやすいこともあります。
SQL自体がコードレビューの対象として見やすいからです。
また、SQLクライントからSQLをそのまま実行できることを大きな強みです。
JPAが向いている場合
JPAが向いているのは、CRUD中心で開発速度やコード量の削減を重視したい開発です。
次のようなケースでは、JPAの相性がよくなりやすいです。
- 基本操作が多い
- エンティティ単位で素直に扱える
- Spring Data JPAを活かしたい
- なるべく定型コードを減らしたい
- ドメインモデルを中心に設計したい
たとえば、管理画面、マスタ管理、社内ツール、比較的シンプルな業務APIなどでは、JPAの恩恵が出やすいです。
保存や取得のたびにSQLを書く必要がないため、実装スピードが上がります。
また、Spring Bootとの相性が良く、周辺の仕組みも含めて使いやすいのは大きな利点です。
チームがJPAに慣れているなら、かなり快適に開発できます。
ただし、JPAが向いているのは「何でも自動でうまくやってくれるから」ではありません。
アプリの構造とJPAの考え方が合っているときに強いという見方の方が、実務ではずれにくいです。
選ぶときの注意点
実務で選ぶときに大事なのは、技術そのものの印象ではなく、チームと案件に合うかです。
よくある失敗は、「流行っているからJPA」「昔から使っているからMyBatis」という決め方です。
これだと、肝心の開発のしやすさが置き去りになりがちです。
見るべきなのは、たとえば次のような点です。
- CRUD中心か、複雑な検索中心か
- SQLを明示的に管理したいか
- チームがJPAの挙動を理解しているか
- 既存システムや既存DBとの整合が必要か
- 将来の改修で、どちらの方が扱いやすいか
ここで一つ注意したいのは、JPAを使ってもSQLの理解は必要ということです。
SQLを書かない場面が増えるだけで、DBアクセスの仕組みから完全に自由になれるわけではありません。
遅い原因を調べるときも、N+1問題を避けるときも、結局はSQLの理解が必要になります。
逆に、MyBatisだから古い、JPAだから先進的、という見方もあまり意味がありません。
どちらも実務で十分使われている選択肢であり、大切なのは適材適所です。
迷ったときは、「どんなクエリを多く書くのか」「誰が保守するのか」を基準にすると判断しやすくなります。
まとめ
MyBatisとJPAの違いは、単に書き方の差ではありません。
SQLを中心に考えるか、オブジェクトを中心に考えるかという、開発の視点そのものが違います。
MyBatisは、SQLを自分でしっかり制御したい場面に向いています。
複雑な検索や集計、既存DBとの付き合いが多い開発では、扱いやすさを感じやすいです。
JPAは、CRUD中心の開発で記述量を減らし、生産性を高めたい場面に向いています。
ただし、便利に使うには内部の仕組みも理解しておく必要があります。
結局のところ、「どちらが優れているか」ではなく、どんな開発にどちらが合うかで選ぶのが実務的です。
技術選定で迷ったときは、案件の性質、チームの理解度、将来の保守まで含めて考えると判断がしやすくなります。


コメント