MyBatisのDynamicSQLにFreeMarkerを採用する

エキサイト株式会社メディア開発佐々木です。

SpringBoot/Javaで既存システムのリビルド開発を行っていますが、ORマッピー(正確にはORマッパーではない)にはMyBatisを採用しています。テーブル構成はなかなか変えられない為、良くも悪くも自由度の高いMyBatisを採用しています。

MyBatisとは

JavaのORマッパーになります。

MyBatisのクエリ生成(デフォルト)

単純な動的クエリはメソッドが用意されているのですが、joinやら分岐やら複雑なSQLになるとそうはいきません。デフォルトはXMLの設定になります。メリットとしてはこういったものになるかと思います。

  • デフォルトの設定
  • 複雑なクエリで複雑なマッピングをXML上で完結できる
  • Javaの型とDBの型とのマッピングが柔軟
  • 1ファイルに複数のクエリを書ける

しかし、XMLを採用しているがゆえのデメリットもあります。

  • XML形式だと、比較演算子で面倒(CDATA[]の中で書かないとエラーになる)
  • XMLの記述が冗長で覚えるのが面倒
  • 複雑なクエリで複雑なマッピングを行えてしまい、XML上でしかテストができないので使わないようにしたい

比較演算子でCDATAを使わないといけないなど、割と面倒です。代替手段がないかの検討を行いました。

FreeMarkerの採用

MyBatisではFreeMarkerもSQLを書くファイルとしてサポートしていたので、採用しています。早速ファイルの中身を比較してみましょう。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.UserDataMapper">
    <select id="findById" resultType="com.example.demo.UserData">
        SELECT 
                 id
               , name
               , birth_year
               , birth_month
               ,birth_day 
        FROM 
               USER_DATA 
        WHERE 
               id = #{id} 
               and now() <![CDATA[ < ]]> birth_month
    </select>
</mapper>

FreeMarkerではこうなります。

findById.ftl

SELECT 
          id
          , name
          , birth_year
          , birth_month
          ,birth_day 
FROM 
          USER_DATA 
WHERE 
           id = <@p name="id" />
          and now() < birth_month

記述量が結構違いますよね。XMLの方が複雑な制御ができたりするのですが、テストしづらいですし、コードを見たときに理解しづらいコードになったりします。メディア開発ではアジリティを大事にしていますので、同じ効果であれば効率のイイものを選択し、リターンがない複雑なものは選択しないように意識しています。

最後に

MyBatisの標準はXMLですが、エキサイトのメディア開発では、使い勝手や開発のアジリティを考えて最適なものを選ぶようにした結果、FreeMarkerを選択しています。小さなことですが、技術や自分たちが抱えてる問題をしっかり把握し、少しずつでも現状にフィットした適切な選択を積み重ねられる組織運営ができればと思います。

エキサイトではフロントエンジニア、バックエンドエンジニア、アプリエンジニアを随時募集しております。長期インターンも歓迎していますので、興味があれば連絡いただければと思います。

www.wantedly.com