読者です 読者をやめる 読者になる 読者になる

GradleでMyBatis Generatorを使う

MyBatisを使ったことがなかったので、評価中です。

MyBatis Generator用のGradleプラグインがあるみたいなので、試してみました。

Gradle - Plugin: com.arenagod.gradle.MybatisGenerator

build.gradle

build.gradle は以下のような感じです。

plugins {
    id "com.arenagod.gradle.MybatisGenerator" version "1.3"
}

mybatisGenerator {
    verbose = true
    configFile = "${projectDir}/src/main/resources/autogen/generatorConfig.xml"
}

generatorConfig.xml

generatorConfig.xml に自動生成のための設定、ルールを書いていきます。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd" >
<generatorConfiguration >
    <classPathEntry location="/path/to/mysql-connector-java-5.1.40.jar" />
    <context id="MySQLTables" targetRuntime="MyBatis3">
        <commentGenerator>
            <property name="suppressDate" value="true" />
        </commentGenerator>
        <jdbcConnection
                driverClass="com.mysql.jdbc.Driver"
                connectionURL="jdbc:mysql://localhost:3306/sampledb"
                userId="root"
                password="" />
        <javaModelGenerator
                targetPackage="sample.domain.model"
                targetProject="src/main/java">
            <property name="enableSubPackages" value="true" />
        </javaModelGenerator>
        <sqlMapGenerator
                targetPackage="sample.domain.mapper"
                targetProject="src/main/resources">
            <property name="enableSubPackages" value="true" />
        </sqlMapGenerator>
        <javaClientGenerator
                targetPackage="sample.domain.mapper"
                targetProject="src/main/java" type="MIXEDMAPPER">
            <property name="enableSubPackages" value="true" />
        </javaClientGenerator>
        <table tableName="%"
               enableInsert="true"
               enableSelectByPrimaryKey="true"
               enableSelectByExample="false"
               enableUpdateByPrimaryKey="true"
               enableUpdateByExample="false"
               enableDeleteByPrimaryKey="true"
               enableDeleteByExample="false"
               enableCountByExample="false"
               selectByExampleQueryId="false"
               modelType="flat">
        </table>
    </context>
</generatorConfiguration>

設定のリファレンスは公式を参照してください。

MyBatis Generator – MyBatis Generator XML Configuration File Reference

なるべく余計なものは生成されないようにする、という方針のもとで、以下を設定しています。

  • javaClientGeneratorのtypeはMIXEDMAPPER

マッピングファイル(XML)とアノテーションによる実装が混在した状態で生成されます。
混在というと複雑なように思われますが、ざっくり言うと、1件のINSERT, 主キーを指定したUPDATE, DELETEに関しては、アノテーションでの定義、それ以外がXMLになりました。

  • tableのxxxByExampleはfalse

⇒ 柔軟な条件によるSELECT, UPDATE, DELETEを行なうためのマッピングを自動生成するオプションですが、いったん無効化しました。
理由として、この類のものは、アプリケーション側の要件に応じて、必要な時に作っていった方がよいように思ったからです。また、MyBatisを使った場合の(JPAと比較しての)メリットとして、SQLを直接扱えることによるわかりやすさがあると思うのですが、 XML中に <if>, <choose>, <set> などの非SQLな構文が混ざって、可読性を損ねている(メリットを潰している)気がします。

ただ、 selectByExample="false" を指定しても、Example系のコードが生成されてしまいました…。

  • tableのmodelTypeはflat

⇒ hierarchicalを指定した場合、主キーは別のクラスとして生成されますが、flatを指定すると、テーブルとクラスが1:1に対応します。

実行

$ ./gradlew mbGenerator

(タスク名が分かりにくいなと思いました…)

疑問

  • 生成されるモデルをLombokで装飾したい
    • MyBatis Generatorはプラグインによって処理を挟めるみたいなので、それでできそう。
  • 生成されるMapperをGroovyコードで出力したい(ヒアドキュメントが使えるため、アノテーションSQLを記述しても、読みやすい)
  • スキーマ変更に追随する場合のベストプラクティス
    • 変更の度に毎回自動生成して上書き、でもよさそうだけど、自動生成後に変更を加えた部分が潰されてしまうリスクがある。