MyBatisの根幹をさわるMyBatisプラグイン機構とその使いみち

アソビュー! Advent Calendar 2022 の 20日目です。

本日の裏面はこちら!

tech.asoview.co.jp

バックエンドエンジニアのアズマです。

今回は半O/Rマッパーとして古くから知られる MyBatis の根幹をさわるMyBatisのプラグイン機構と、その使い道をご紹介します。

このプラグインができること

MyBatisプラグインとは、MyBatisを使ったデータベースへの操作に割り込んで処理を追加できる機能です。

例えば、

  • データの検索や更新
  • パラメータのバインド
  • データベース接続の切断時

など、大抵のデータベースに対する操作に対してなんらかの処理を割り込みが可能です。(=インターセプトする)

検索したSQLマッピングのIDを出力する

MyBatisからすべての検索SQLを行うときに、そのidを出力する実装例です。 プラグインの設定は、MyBatisの全体設定である mybatis-config.xml に記載しています。

実行するSQLとマッピング設定

出力した結果(抜粋)

マッピング定義した selectItem が、その定義パッケージ名(=MyBatisのnamespace)とともに出力されてますね。

c.g.a.s.c.m.SqlIdLoggingInterceptor      : sql-id: com.github.apz.sample.mapper.ItemMapper.selectItem

ログ出力以外の適用について

このプラグイン機能はかなり強力で、MyBatis全体の振る舞いに影響します。

例えばSQLへパラメータをバインドするときに必ず別の値を設定することも可能である*1ため、大抵は処理前後にログ出力を差し込んでの動作確認やMyBatis標準のログ以外にも追加で常に出力する使い方になります。

次の例は、SQLへパラメータをバインドする処理に差し込む実装です。

プラグインと設定

すべてのSQL実行時にパラメータをバインドする前後のSQLをログ出力する設定と実装です。

実行ログ(抜粋)

この例では接続データベースにMySQL、接続プールにHikari Connection Poolを利用しています。実行前はパラメータが未設定の状態、実行後はパラメータが格納されたSQLになっているのを確認できます。

[nio-8080-exec-1] c.g.a.s.c.m.ParameterBindingInterceptor  : before: HikariProxyPreparedStatement@416707395 wrapping com.mysql.cj.jdbc.ClientPreparedStatement: SELECT
            id
            , name
            , register_time
        FROM
            item
         WHERE id = ** NOT SPECIFIED **
[nio-8080-exec-1] c.g.a.s.c.m.ParameterBindingInterceptor  : after : HikariProxyPreparedStatement@416707395 wrapping com.mysql.cj.jdbc.ClientPreparedStatement: SELECT
            id
            , name
            , register_time
        FROM
            item
         WHERE id = '1'
[nio-8080-exec-2] c.g.a.s.c.m.SqlIdLoggingInterceptor      : sql-id: com.github.apz.sample.mapper.ItemMapper.selectItem

その他の用途

MyBatisでSQLを記述する方法には

これらが用意されており、それぞれのテンプレートから生成したSQLを確認するときにも有用です。さらにはSQLテンプレートを自作したときの動作確認で非常に役立つでしょう。

最後に

アソビューでは一緒に働くメンバーを大募集しています。カジュアル面談もありますので、少しでも興味があればお気軽にご応募いただければと思います。

www.asoview.com

参考記事

https://mybatis.org/mybatis-3/ja/configuration.html#plugins

*1:強制的にパラメータ値を変更する場合は、特定の値を完全にブロックするような特殊要件があるときに利用します