MyBatis Generator(MBG)は、データベースのテーブル定義を読み取って、Javaのモデルクラス・Mapperインターフェイス・SQLを生成するツールです。最新版は2026年4月8日公開の2.0.0で、動かすにはJava 17以上が必要です。日本語の解説記事の多くは1.3系・1.4系を前提にしているため、同じ設定を書いても手元に出るファイルが記事と違う、ということが起きます。この記事では、2.0.0をMavenで実行した結果をもとに、生成物を決める設定、生成されたMapperの呼び出し方、再生成で自作コードを消さない設定までを順に説明します。
まとめ
MBGで何が生成されるかは<context>のtargetRuntimeで決まります。既定はMyBatis3DynamicSqlで、出力はモデル・Mapper・サポートクラスの3ファイルです。Mapper XMLもPostExample.javaのような条件クラスも作られません。古い記事と同じファイル構成が欲しいならtargetRuntime="MyBatis3"と<clientGenerator type="XMLMAPPER">を明示します。
実行はmvn mybatis-generator:generateです。JDBCドライバはプラグインの<dependencies>に書きます。生成コードはjakarta.annotation.Generatedを使うので、Spring Bootを使わないプロジェクトではjakarta.annotation-apiも依存に足します。
再生成で手書きのメソッドを残したいなら、2.0.0ではjavaMergeEnabledをtrueにしてJavaParserをプラグインのクラスパスに入れます。このときsuppressAllCommentsはtrueにしないでください。trueにすると生成目印の@Generatedが出なくなり、目印のないファイルを再生成でマージしたときに生成メソッドが重複して、コンパイルが通らなくなります。
targetRuntime別に生成されるファイル
次の表は、view_countを追加した6列のテーブル1つ(POST)に対して、2.0.0のランタイムとMapper出力設定を変えて実行した結果です。コメント設定は既定のままで、行数には@Generatedの行も含みます。
| targetRuntime | clientGenerator type | 生成されたファイル | 合計行数 |
|---|---|---|---|
| MyBatis3DynamicSql(既定) | 不要(指定しても無視) | Post/PostMapper/PostDynamicSqlSupport | 306行 |
| MyBatis3 | XMLMAPPER | Post/PostExample/PostMapper/PostMapper.xml | 1,023行 |
| MyBatis3 | ANNOTATEDMAPPER | Post/PostExample/PostMapper/PostSqlProvider | 1,041行 |
| MyBatis3Simple | XMLMAPPER | Post/PostMapper/PostMapper.xml | 175行 |
同じテーブルでも、レガシーのMyBatis3は既定ランタイムの3倍以上のコードを出します。公式のQuick Start Guideも、このランタイムについて生成コードの量が非常に多く、検索条件の組み立てが限られて拡張しにくいと書いています。
既定のMyBatis3DynamicSqlで出るもの
targetRuntimeを省略するとこのランタイムになります。PostMapperには@Mapperが付き、count・select・selectOne・selectByPrimaryKey・insert・insertMultiple・insertSelective・update・updateByPrimaryKey・delete・deleteByPrimaryKeyなどがdefaultメソッドとして並びます。SQLはPostDynamicSqlSupportのテーブル・列オブジェクトを使ってJavaのDSLで組み立てます。
生成コードの実行時にはmybatis-dynamic-sqlの2.0.0以降が必要です(2.0.0のリリースノート)。生成されたdeleteByPrimaryKey(Long id_)のように引数名の末尾に_が付くのは、static importした列オブジェクトidと名前が重ならないようにMBGが付けたものです。気になる場合は2.0.0で追加されたuseSnakeCaseIdentifiersを使うと、列オブジェクト側がORDER_MASTERのような大文字スネークケースになります。DSLの書き方はMyBatis Dynamic SQLの使い方|if・where・foreachと2.0.0の型安全DSLを実行結果で解説で詳しく扱っています。
レガシーのMyBatis3とMyBatis3Simple
PostExample.javaとPostMapper.xmlが出てくる古い記事は、すべてこの系統です。MyBatis3はExampleクラスで任意の条件を組める代わりにコード量が最も多く、MyBatis3SimpleはExampleを作らず、Mapperのメソッドをinsert・selectByPrimaryKey・selectAll・updateByPrimaryKey・deleteByPrimaryKeyの5つに絞ります。レガシー系では<clientGenerator>のtypeが必須で、省略するとInvalid clientGenerator type "null"で止まります。XMLを出す設定なのに<sqlMapGenerator>が無い場合はSqlMapGeneratorConfiguration is requiredで止まります。
既存プロジェクトがこの形式で動いているなら、乗り換えを急ぐ理由はありません。新規に入れるなら既定ランタイムを選びます。Exampleクラスは条件のANDとORを重ねると読みにくくなり、並び順も文字列で渡すしかないためです。
ANNOTATEDMAPPERでもXMLが出て起動に失敗するケース
clientGeneratorのリファレンスは、ANNOTATEDMAPPERについてNo XML mapper files will be generatedと書いています。ところが2.0.0で<sqlMapGenerator>を設定に残したままtype="ANNOTATEDMAPPER"にすると、302行・15ステートメントのPostMapper.xmlも出力されました。
この状態でMapperを登録すると、MyBatisはアノテーションと同じパッケージのXMLを両方読み込み、起動時に次の例外で止まります。
Exception in thread "main" java.lang.IllegalArgumentException: Mapped Statements collection already contains key com.example.mapper.PostMapper.updateByExampleSelective. please check com/example/mapper/PostMapper.xml and com/example/mapper/PostMapper.java (best guess)
XMLを消すとcountByExampleは正常に動きました。XMLMAPPERからANNOTATEDMAPPERへ切り替えるときは、設定から<sqlMapGenerator>を外し、出力済みのXMLも削除します。
recordで生成するときの属性名
2.0.0では、Kotlin以外のランタイムでモデルをJavaのrecordとして出せます。<context>ではdefaultModelType="record"、テーブル単位で上書きするときの<table>側の属性名はmodelTypeです。recordは不変なので、自動採番のキーを書き戻すテーブルには使えません。recordの性質はJavaのレコードクラス(record)とは?使い方・コンストラクタ・継承できない理由をJava 25で実測を参照してください。
Mavenでコードを生成する手順
公式が用意している実行方法は、コマンドライン・Ant・Maven・Javaプログラム・Eclipseの5つです(Running MyBatis Generator)。この記事では、pom.xmlで生成ツールとJDBCドライバの版を指定できるMavenプラグインを使います。
pom.xmlのプラグイン・JDBCドライバ設定
<build>
<plugins>
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>2.0.0</version>
<dependencies>
<!-- JDBCドライバはプロジェクトの依存ではなく、ここに書く -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>2.5.252</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>
プラグインのクラスパスには、初期状態ではMBG本体しか入っていません(Running with Maven)。JDBCドライバをプロジェクトの<dependencies>に書いても、生成時には見えません。
生成されたコードをコンパイル・実行する側には、次の依存が要ります。H2で実行する場合は、プラグイン内の依存とは別に、プロジェクト側の<dependencies>にもcom.h2database:h2:2.5.252を追加します。
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.19</version>
</dependency>
<dependency>
<groupId>org.mybatis.dynamic-sql</groupId>
<artifactId>mybatis-dynamic-sql</artifactId>
<version>2.0.0</version>
</dependency>
<!-- Spring Bootを使わない場合だけ明示する(生成コードが@Generatedを使うため) -->
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<version>3.0.0</version>
</dependency>
jakarta.annotation-apiを外してコンパイルするとパッケージjakarta.annotationは存在しませんで失敗しました。Spring Bootのspring-boot-starter 4.1.0はjakarta.annotation-api 3.0.0を依存に含むので、Spring Bootのプロジェクトでは追加不要です。
generatorConfig.xmlの接続・生成先設定
MBGは接続先DBのテーブル定義を読むので、生成の前にテーブルを作っておきます。検証では次のDDLをH2のファイルDBに流しました(表の行数計測では、これにview_count INTを足した6列で実行しています)。
CREATE TABLE IF NOT EXISTS post (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(200) NOT NULL,
author_id INT,
status VARCHAR(20),
created_at TIMESTAMP
);
Mavenプラグインが既定で読むのはsrc/main/resources/generatorConfig.xmlです。別の場所に置くならconfigurationFileパラメータで指定します。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration PUBLIC
"-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"https://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<!-- targetRuntimeを省略するとMyBatis3DynamicSql -->
<context id="dsql">
<commentGenerator>
<!-- @Generatedから日時を外し、再生成のたびに全行が差分になるのを防ぐ -->
<property name="suppressDate" value="true" />
</commentGenerator>
<jdbcConnection driverClass="org.h2.Driver"
connectionURL="jdbc:h2:./db/sample" userId="sa" password="" />
<modelGenerator targetPackage="com.example.model" targetProject="src/main/java" />
<clientGenerator targetPackage="com.example.mapper" targetProject="src/main/java" />
<table tableName="POST" domainObjectName="Post">
<generatedKey column="ID" sqlStatement="JDBC" identity="true" />
</table>
</context>
</generatorConfiguration>
2.0.0では要素名がjavaModelGeneratorからmodelGeneratorへ、javaClientGeneratorからclientGeneratorへ変わりました。旧名も警告付きで動きます。targetProjectをMAVENにすると、出力先はtarget/generated-sources/mybatis-generatorになります。生成物をGitで管理するなら、上の例のようにsrc/main/javaを直接指定します。
<generatedKey>は省略しないでください。レガシーのMyBatis3で省略したところ、insertがID列にnullを渡し、H2 2.5.252では列 "ID" にはnull値が許されていませんで失敗しました。スキーマ変更をFlywayとは?Spring Bootのマイグレーション設定と命名規則・Spring Boot 4の変更点【2026年8月】で管理しているなら、マイグレーションを流したDBに対してMBGを走らせる順番にすると、生成物とスキーマがずれません。
mvn mybatis-generator:generateの実行と上書き設定
mvn mybatis-generator:generate
mvn -Dmybatis.generator.overwrite=true mybatis-generator:generate
overwriteの既定はfalseです。2回目以降の実行では既存のJavaファイルを上書きせず、Existing file not overwritten, the generated file is saved as ...Post.java.1という警告を出してPost.java.1を横に書き出します。ビルドは成功するので、変更が反映されないと感じたら.java.1が増えていないかを見てください。通常のXML出力は、Javaファイル向けのoverwrite設定にかかわらずマージして上書きされます。ただし、公式プラグインのUnmergeableXmlMappersPluginを入れると、XMLもJavaと同じくoverwriteに従います。
Mavenを使わない場合は、mybatis-generator-core-2.0.0.jarをjava -jarで起動し、-configfileで設定ファイルを渡します。
生成されたMapperの呼び出し例
生成直後のMapperは、そのままCRUDに使えます。以下は、MyBatisのConfigurationにMapperを登録し、H2のインメモリDBに先ほどのDDLを流してから実行したコードと出力です。Spring Bootを使う場合、SqlSessionの組み立ては後述のスターターが行います。
MyBatis3DynamicSqlのselect・count・update
// import文は省略(PostDynamicSqlSupport.* と SqlBuilder.* を static import)
public static void main(String[] args) {
var ds = new UnpooledDataSource("org.h2.Driver", "jdbc:h2:mem:t;INIT=RUNSCRIPT FROM 'db/schema.sql'", "sa", "");
var conf = new Configuration(new Environment("dev", new JdbcTransactionFactory(), ds));
conf.addMapper(PostMapper.class);
try (SqlSession s = new SqlSessionFactoryBuilder().build(conf).openSession(true)) {
PostMapper m = s.getMapper(PostMapper.class);
Post p = new Post(); p.setTitle("MBG入門"); p.setAuthorId(1); p.setStatus("draft"); p.setCreatedAt(LocalDateTime.now());
System.out.println("insert=" + m.insert(p) + " id=" + p.getId()); // generatedKeyで採番値が入る
Post q = new Post(); q.setTitle("Dynamic SQL"); q.setAuthorId(2); q.setStatus("published");
m.insertSelective(q);
System.out.println("count(published)=" + m.count(c -> c.where(status, isEqualTo("published"))));
var rows = m.select(c -> c.where(authorId, isIn(1, 2)).and(title, isLike("%MBG%")).orderBy(id));
System.out.println("select=" + rows.size() + " title=" + rows.get(0).getTitle());
System.out.println("update=" + m.update(c -> c.set(status).equalTo("published").where(id, isEqualTo(p.getId()))));
System.out.println("byPk=" + m.selectByPrimaryKey(p.getId()).map(Post::getStatus).orElse("none"));
System.out.println("delete=" + m.deleteByPrimaryKey(q.getId()));
System.out.println("count(all)=" + m.count(c -> c));
}
}
実行結果は次のとおりです(2件登録して1件更新・1件削除した結果)。
insert=1 id=1
count(published)=1
select=1 title=MBG入門
update=1
byPk=published
delete=1
count(all)=1
条件はwhere(列, 条件)とand(...)をつないで書きます。count(c -> c)のように条件を付けなければ全件が対象です。主キー以外の条件で1件だけ取りたいときは、Optionalを返すselectOneを使います。例ではopenSession(true)で自動コミットにしています。引数なしで開いた場合はs.commit()を呼ぶまで確定しません。
MyBatis3のExampleクラスによる検索条件の指定
PostExample ex = new PostExample();
ex.createCriteria()
.andStatusEqualTo("published")
.andAuthorIdIn(List.of(1, 2));
ex.or().andTitleLike("%MBG%"); // OR条件は別のCriteriaとして足す
ex.setOrderByClause("ID DESC"); // 並び順は文字列で渡す
long n = mapper.countByExample(ex);
List<Post> rows = mapper.selectByExample(ex);
3件登録した状態で実行すると、n=2、結果は[Dynamic SQL, MBG入門]でした。createCriteria()で作った条件はANDで結ばれ、or()で足したCriteriaとはORで結ばれます。
注意点はsetOrderByClauseです。生成されたXMLはorder by ${orderByClause}で、値をバインドせず文字列のままSQLに埋め込みます。画面から受け取った並び替えキーをそのまま渡すとSQLインジェクションになるので、許可した列名だけを選ぶ形にします。
Spring BootのMapper登録と依存性注入
Spring Bootではmybatis-spring-boot-starterを入れます。2026年10月時点の最新は4.1.0で、4.x系はSpring Boot 4系向けです(MyBatis Spring Boot Autoconfigure)。スターターは既定で@Mapperが付いたインターフェイスを探して登録します。
@SpringBootApplication
@MapperScan("com.example.mapper") // レガシー系の生成Mapperには@Mapperが付かない
public class App { }
@Service
public class PostService {
private final PostMapper postMapper;
public PostService(PostMapper postMapper) { this.postMapper = postMapper; }
public List<Post> published() {
return postMapper.select(c -> c.where(status, isEqualTo("published")));
}
}
既定ランタイムの生成Mapperには@Mapperが付くので、DataSourceを設定し、MapperをSpring Bootの自動スキャン対象パッケージに配置すれば、自動登録して注入できます。レガシーのMyBatis3で生成したMapperには@Mapperが付かなかったため、@MapperScanでパッケージを指定します。Spring Boot側の版の選び方はSpring Bootバージョン一覧とサポート期限(EOL)、最小構成はSpring Bootとは|4.1系の依存名の変更と最小Web APIの作り方にまとめています。
再生成で自作コードを消さない設定
テーブルに列を足すたびにMBGを流し直すと、生成ファイルに手で足したメソッドが問題になります。1.x系ではJavaのマージがEclipseプラグインにしか無く、Mavenで回す現場では「生成物には手を入れない」が原則でした。2.0.0でJavaのマージがコアに入り、Eclipseなしで使えるようになっています。
javaMergeEnabledとJavaParserによるJavaマージ設定
<plugin>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-maven-plugin</artifactId>
<version>2.0.0</version>
<configuration>
<javaMergeEnabled>true</javaMergeEnabled>
</configuration>
<dependencies>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>2.5.252</version>
</dependency>
<dependency>
<groupId>com.github.javaparser</groupId>
<artifactId>javaparser-core</artifactId>
<version>3.28.2</version>
</dependency>
</dependencies>
</plugin>
この設定で、生成済みのPostMapperに自作メソッドを1つ足し、テーブルにview_count列を追加してから再生成しました。自作メソッドは残り、PostにはviewCountのフィールドとgetter・setterが追加され、.java.1は出ませんでした。
JavaParserを入れ忘れると、生成はA required class was missing ... com/github/javaparser/ast/body/BodyDeclarationでBUILD FAILUREになります。公式の依存一覧が挙げる版は3.28.0で、検証では2026年10月時点の最新3.28.2を使いました。
マージで消えるものとsuppressAllCommentsの罠
マージは生成要素に付く@Generatedを目印にしています。そのため、次の3点に注意が要ります。
- 自作メソッドの直前のコメントは消えた:行コメントもJavaDocも、再生成後には残っていませんでした。説明はメソッド本体の中か、別ファイルに書きます。
- 生成要素に後から付けたアノテーションは保持されない:公式のリリースノートが明記しています。必要ならプラグインを書いて生成時に付けます。
- suppressAllCommentsはマージを壊す:trueにすると
@Generatedが出なくなります。既存ファイルに生成目印がない状態で再生成すると、既存の生成メソッドを自作扱いで残し、新しい生成メソッドを足すため、同名のメソッドとフィールドが重複してコンパイルエラーになりました。
コメントを減らしたいならminimizeCommentsを使います。こちらは@Generated("org.mybatis.generator.api.MyBatisGenerator")だけを残すので、再生成を2回重ねてもマージが効きました。suppressDateで日時だけ外す方法もあり、再生成のたびに全行が差分になるのを防げます。各プロパティの説明はcommentGeneratorのリファレンスにあります。なお、XMLファイル側の目印は2.0.0でも@mbg.generatedコメントのままです。
Eclipse・Gradleから実行する場合
Eclipseでは、MarketplaceでMyBatis Generatorを検索して入れるか、更新サイトhttps://jeffgbutler.github.io/mybatis-generator-update-site/を登録します(Running with Eclipse)。Eclipseのランナーは、マージに使うJavaParserを自動でクラスパスに加えます。
Gradleは公式の実行方法一覧に入っていません。Gradleで回すなら、サードパーティ製のプラグインを使うか、mybatis-generator-coreをコマンドラインと同じ形で起動するタスクを書くことになります。サードパーティ製を選ぶときは、そのプラグインが同梱・指定できるMBGの版が2.0.0に追随しているかを先に確認してください。
1.4.2から2.0.0への移行チェックリスト
公式は影響を最小限に抑えたとしていますが、次の項目は設定かビルドの見直しが必要です。
| 確認項目 | 1.4.2まで | 2.0.0 |
|---|---|---|
| 実行するJava | Java 8以上 | Java 17以上 |
| Dynamic SQLの依存 | 1.x系 | 2.0.0以降 |
| 日付型 | useJSR310Typesで切替 | プロパティ削除・JSR-310が既定 |
| Javaの生成目印 | 非標準JavaDocタグ | jakarta.annotation.Generated |
| Javaのマージ | Eclipseのみ | javaMergeEnabledで全ランナー |
| 要素名 | javaModelGenerator等 | modelGenerator等(旧名は警告) |
最初に効いてくるのは日付型です。DATE・TIME・TIMESTAMPは常にLocalDate・LocalTime・LocalDateTimeになり、1.4系でjava.util.Dateのまま運用していたプロジェクトは、DTO変換やテストがまとめてコンパイルエラーになります。java.util.Dateを続けるなら、<javaTypeResolver>のtypeにorg.mybatis.generator.internal.types.DateForcingJavaTypeResolverを指定します。Java 8のままのプロジェクトには2.0.0を入れられないので、その場合は1.4.2に留めます。
プラグインを自作している場合は影響が大きくなります。ContextからgetConnection()が削除され、IntrospectedTable.getTargetRuntime()はgetKnownRuntime()に置き換わりました。MyBatis以外のO/Rマッパーへの乗り換えも視野にあるなら、Java ORM(O/Rマッパー)の種類と選び方|Hibernate・MyBatis・jOOQを比較【2026年10月】で比較できます。
生成されない・反映されないときの切り分け
実行中に出たメッセージから原因を引けるようにまとめます。
| 症状・メッセージ | 原因 | 対処 |
|---|---|---|
| ドライバのクラスが見つからない | プラグインのクラスパスにMBG本体しか無い | プラグインの依存へ追加 |
| Post.java.1 が増える | overwriteが既定false | overwrite=true かマージ有効化 |
| パッケージjakarta.annotationは存在しません | 注釈APIが未導入 | jakarta.annotation-api を追加 |
Invalid clientGenerator type "null" |
レガシー系でtype省略 | XMLMAPPER等を指定 |
| Mapped Statements collection already contains key | 注釈とXMLが重複 | sqlMapGeneratorとXMLを削除 |
| BodyDeclaration が見つからない | JavaParser未追加 | javaparser-core を追加 |
| テーブルが生成されない | tableName・スキーマの不一致 | 大文字小文字とschemaを確認 |
<table tableName="%">と書くとスキーマ内の全テーブルが対象になりますが、監査用や一時テーブルまで生成されます。対象は明示して列挙し、不要な列は<ignoreColumn>で外します。生成したコードを業務システムへ組み込む段階で設計の相談が必要なら、フルスクラッチ開発の支援もご覧ください。
よくある質問
MyBatis Generatorの最新バージョンは?
2026年10月16日時点の最新は2.0.0(2026年4月8日公開)です。Maven Centralのメタデータでもreleaseは2.0.0で、その前の版は1.4.2(2023年2月20日)でした。
mybatis-generator-coreとmybatis-generator-maven-pluginの違いは?
mybatis-generator-coreが生成エンジン本体で、java -jarやJavaコードから呼ぶときに使います。mybatis-generator-maven-pluginはそれをMavenのゴールとして呼ぶラッパーで、内部でcoreを使います。Mavenから使うならプラグインだけを書けば足ります。
generatorConfig.xmlはどこに置く?
Mavenプラグインの既定はsrc/main/resources/generatorConfig.xmlです。別の場所ならconfigurationFile(${mybatis.generator.configurationFile})で指定します。DBのパスワードを書くファイルなので、<properties>要素で外部ファイルから読み込み、そのファイルはリポジトリに入れない運用にします。
Exampleクラスが生成されないのはなぜ?
既定のtargetRuntimeがMyBatis3DynamicSqlで、このランタイムはExampleクラスを作らないためです。targetRuntime="MyBatis3"を指定し、<clientGenerator type="XMLMAPPER">と<sqlMapGenerator>を併せて書くと、PostExample.javaとMapper XMLが生成されます。
GradleでMyBatis Generatorは使える?
公式のGradleプラグインはありません。サードパーティ製のプラグインを使うか、mybatis-generator-coreをコマンドラインと同じ引数で起動するタスクを書きます。どちらの場合も、MBG 2.0.0を実行するJavaは17以上が必要です。