2
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

この記事では、Java でDBアクセスを実装するときの ORM である MyBatis の概要を記載します。簡単な動作例まで含めます。

MyBatis とは

MyBatis は、SQL とJavaのメソッドを対応づける永続化フレームワークです。Apache License 2.0 で公開されています。

一般的な ORM(JPA / Hibernate など)が「JavaのオブジェクトとDBのテーブルをマッピングする」のに対し、MyBatis は Javaのメソッドと SQL 文をマッピングする という発想をとります。SQL を自分で書き、その実行と結果のマッピング部分を肩代わりしてくれるツールになります。

このため MyBatis は厳密には ORM ではなく「SQLマッパー」と呼ばれることもあるようです。

誕生の経緯

MyBatis のルーツは iBATIS というプロジェクトです。

iBATIS は2002年ごろに登場したSQLマッピングフレームワークで、当時 Apache Software Foundation の傘下で開発されていました。2010年に開発チームが Apache から Google Code へ移り、その際に名前を iBATIS から MyBatis へ変更 しています。

現在広く使われているのは iBATIS 3.0 からフォークされた MyBatis 3 系で、開発は iBATIS のオリジナル開発者を含むチームが引き継いでいます。

開発環境

動作例で使う環境は以下のとおりです。執筆時点(2026年6月)の最新版を使います。

  • OS:Windows 11
  • エディタ:VSCode
  • Java 25
  • Gradle(Groovy DSL)
  • MyBatis 3.5.19
  • H2 Database(動作確認用のインメモリDB)

簡単な動作例

ここでは Spring などを使わず、MyBatis 単体で User を1件取得するところまでを書きます。最小構成で動きを見るのが目的です。

依存関係

build.gradle
dependencies {
    implementation 'org.mybatis:mybatis:3.5.19'
    implementation 'com.h2database:h2:2.3.232'
}

エンティティ

マッピング先のクラスを用意します。普通の POJO です。

src/main/java/com/example/User.java
package com.example;

public class User {
    private Long id;
    private String name;

    // getter / setter は省略
}

Mapper インターフェース

SQL を対応づけるインターフェースを定義します。MyBatis ではこのインターフェースのメソッドが、後述のXML(またはアノテーション)に書いた SQL と紐づきます。

src/main/java/com/example/UserMapper.java
package com.example;

public interface UserMapper {
    User findById(Long id);
}

Mapper XML

SQL を XML に書きます。namespace で対象のインターフェースを指定し、id でメソッド名と対応づけます。

src/main/resources/com/example/UserMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "https://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.example.UserMapper">
  <select id="findById" parameterType="long" resultType="com.example.User">
    SELECT id, name FROM users WHERE id = #{id}
  </select>
</mapper>

#{id} の部分が、メソッドに渡した引数で置き換わります。これは PreparedStatement のプレースホルダ(?)に変換されるので、SQL インジェクション対策にもなります。

設定ファイル

接続情報と、読み込む Mapper を設定します。

src/main/resources/mybatis-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  "https://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
  <environments default="dev">
    <environment id="dev">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="org.h2.Driver"/>
        <property name="url" value="jdbc:h2:mem:testdb"/>
        <property name="username" value="sa"/>
        <property name="password" value=""/>
      </dataSource>
    </environment>
  </environments>
  <mappers>
    <mapper resource="com/example/UserMapper.xml"/>
  </mappers>
</configuration>

実行

SqlSessionFactory を作り、セッションを開いて Mapper を呼び出します。

src/main/java/com/example/Main.java
package com.example;

import java.io.InputStream;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class Main {
    public static void main(String[] args) throws Exception {
        InputStream input = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(input);

        try (SqlSession session = factory.openSession()) {
            UserMapper mapper = session.getMapper(UserMapper.class);
            User user = mapper.findById(1L);
            System.out.println(user.getName());
        }
    }
}

session.getMapper() でインターフェースの実装が動的に生成され、findById() を呼ぶと対応する SQL が実行されます。実装クラスを自分で書かなくてよいのは MyBatis の便利なところだと思います。

XML ではなくアノテーションで SQL を書くこともできます。

public interface UserMapper {
    @Select("SELECT id, name FROM users WHERE id = #{id}")
    User findById(Long id);
}

短いSQLならアノテーションが手軽ですが、複雑なSQLや動的SQLはXMLの方が書きやすいです。

得意なこと

実際に使ってみて、MyBatis が向いていると感じた場面を挙げます。

SQL を自分で完全にコントロールできる

発行される SQL がそのまま XML に書いてあるので、何が実行されるかが明確です。複雑な JOIN、ウィンドウ関数、DB固有の構文なども、SQL をそのまま書けば使えます。JPA だと JPQL や Criteria API で表現しづらいクエリも、MyBatis なら素直に書けます。

既存DB・レガシーDBとの相性

正規化されていないテーブルや、後から構造を変えにくい既存DBに対しても、SQL 側で吸収できるので扱いやすいです。「DB設計が先にあって、それに合わせてアプリを作る」タイプの案件では特に効いてきます。

動的SQL

検索条件によって WHERE 句を組み立てる、といった処理を XML のタグで書けます。

<select id="search" resultType="com.example.User">
  SELECT id, name FROM users
  <where>
    <if test="name != null">
      AND name LIKE #{name}
    </if>
    <if test="id != null">
      AND id = #{id}
    </if>
  </where>
</select>

<where> は、中身が空なら WHERE ごと出力せず、先頭の余分な AND も自動で除いてくれます。文字列結合でSQLを組み立てる処理をJava側に書かずに済みます。

苦手なこと

逆に、使っていて手間に感じた点です。

SQL を全部自分で書く

裏返しですが、CRUD のような単純な処理でも基本は自分で SQL を書きます。JPA なら save()findAll() が最初から用意されているのと比べると、定型処理の記述量は増えます。テーブル数が多いとそのぶん Mapper も増えます。

DBの差異を吸収しにくい

SQL を直接書く以上、DB を MySQL から PostgreSQL に変える、といった場合に方言部分の書き換えが必要になることがあります。JPA のように「DBが変わっても基本そのまま」とはいきにくいです。

XML の記述・管理コスト

XML ベースで書くと、インターフェース・XML・エンティティを行き来することになります。規模が大きくなると、この対応関係の管理がそれなりに負担になります。

こうした定型処理の記述量を減らすために、MyBatis-PlusMyBatis Generator といった補助ツールもあります。MyBatis-Plus は基本的なCRUDメソッドを自動で提供してくれるもので、中国を中心に広く使われています。MyBatis 単体の手間が気になる場合は検討する価値があります。

類似サービスとの比較

Java の DB アクセス手段を、ざっくり比較するとこんな感じです。

ツール スタイル SQL の書き方 向いている場面
MyBatis SQLマッパー 自分で書く(XML/アノテーション) SQLを細かく制御したい、既存DB
JPA / Hibernate ORM 自動生成(JPQL等で補完) DB設計をアプリ主導でやる、定型CRUDが多い
Spring Data JDBC 軽量ORM 一部自動 + 自分で書く JPAより薄く使いたい
jOOQ SQLビルダー Javaコードで型安全に組み立て SQLを書きたいが型チェックも欲しい

MyBatis と JPA はよく比較されますが、設計思想が違うので「どちらが優れているか」というより「SQLを自分で握りたいか、フレームワークに任せたいか」の選択だと考えています。SQLが複雑になりがちな業務システムでは MyBatis が選ばれやすい印象です。

まとめ

MyBatis は、Java のメソッドと SQL を対応づける SQLマッパーです。iBATIS をルーツに持ち、SQL を自分で書く前提で、その実行と結果マッピングを引き受けてくれます。

SQL を細かくコントロールしたい場合や既存DB相手の開発では強みが出ますが、定型的なCRUDが多い場合は記述量が増えるトレードオフがあります。JPA とは思想が違うので、案件の性質に合わせて選べるといいですね。

参考

2
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?