kagamihogeの日記

kagamihogeの日記です。

MyBatis ThymeleafのSQL Generator

MyBatis ThymeleafSQL生成機能であるSQL GeneratorはMyBatisとは独立して使用できる。基本的には他のO\Rマッパーと共に使用する。今回はmybatis-thymeleaf単体で使用可能な事を示すためにあえて他の依存性は何も追加せずにSQL生成のみ試す。

ソースコードなど

build.gradle

plugins {
  id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '17'

repositories {
  mavenCentral()
}

dependencies {
  implementation 'org.mybatis.scripting:mybatis-thymeleaf:1.0.4'
}

使ってみる

import java.util.Map;
import org.mybatis.scripting.thymeleaf.SqlGenerator;

public class SqlGeneratorSample1 {
  public static void main(String[] args) {
    SqlGenerator sqlGenerator = new SqlGenerator();

    Map<String, Object> params = Map.of("id", 100);
    String sql = sqlGenerator.generate("""
        select
            id
            , username
        from
            my_users
        where
            id = /*[# mb:p="id"]*/ 1 /*[/]*/
        """, params);

    System.out.println(sql);
  }
}

出力結果は以下になる。

select
    id
    , username
from
    my_users
where
    id = #{id}

プレースホルダの形式をMyBatisから変更

デフォルト設定だとプレースホルダの形式はMyBatisの#{xxx}なので、これをJdbcTemplateなどで使われる:xxxに変更する。

import org.mybatis.scripting.thymeleaf.SqlGenerator;
import org.mybatis.scripting.thymeleaf.SqlGeneratorConfig;
import org.mybatis.scripting.thymeleaf.processor.BindVariableRender;

    SqlGeneratorConfig config = SqlGeneratorConfig.newInstanceWithCustomizer(c -> c.getDialect()
        .setBindVariableRenderInstance(BindVariableRender.BuiltIn.SPRING_NAMED_PARAMETER));
    SqlGenerator sqlGenerator = new SqlGenerator(config);

出力結果は以下になる。

(略)
where
    id = :id

カスタム変数

パラメータとは別にカスタム変数としてSQL生成時に使用する値を渡せる。カスタム変数は二種類ありSqlGeneratorに指定するデフォルトカスタム変数と、生成時に指定するカスタム変数がある。

import java.time.LocalDateTime;
import java.util.Map;
import org.mybatis.scripting.thymeleaf.SqlGenerator;
import org.mybatis.scripting.thymeleaf.SqlGeneratorConfig;
import org.mybatis.scripting.thymeleaf.processor.BindVariableRender;

public class SqlGeneratorSample1 {
  public static void main(String[] args) {
    SqlGeneratorConfig config = SqlGeneratorConfig.newInstanceWithCustomizer(c -> c.getDialect()
        .setBindVariableRenderInstance(BindVariableRender.BuiltIn.SPRING_NAMED_PARAMETER));
    SqlGenerator sqlGenerator = new SqlGenerator(config);

    Map<String, Object> defaultCustomVariables = Map.of("anyStaticValue", "hoge");
    sqlGenerator.setDefaultCustomVariables(defaultCustomVariables);

    Map<String, Object> customVariables = Map.of("now", LocalDateTime.now());
    Map<String, Object> params = Map.of("id", 100);

    String sql = sqlGenerator.generate("""
        select
            id
            , /*[# th:utext=\"${now} "]*/ '2023-05-07T20:20:47' /*[/]*/
        from
            my_users
        where
            id = /*[# mb:p="id"]*/ 1 /*[/]*/
            /*[# th:if="${anyStaticValue} == 'hoge'"]*/and hoge = 'hoge'/*[/]*/

        """, params, customVariables);

    System.out.println(sql);
  }
}

出力結果は以下になる。

select
    id
    , 2023-05-07T20:25:20.484348200
from
    my_users
where
    id = :id
    and hoge = 'hoge'

カスタムバインド変数の追加

SQLテンプレート処理でバインド変数を追加生成する場合にこれを使う。たとえば、以下はドキュメントの例そのままだが、nameLIKEで使うためにエスケープ処理したバインド変数patternNameを追加している。このためにSqlGeneratorcustomBindVariableBinderにバインド変数追加用のBiConsumer<String, Object>を指定する。

import java.util.HashMap;
import java.util.Map;
import org.mybatis.scripting.thymeleaf.SqlGenerator;
import org.mybatis.scripting.thymeleaf.SqlGeneratorConfig;
import org.mybatis.scripting.thymeleaf.processor.BindVariableRender;

public class SqlGeneratorSample2 {
  public static void main(String[] args) {
    SqlGeneratorConfig config = SqlGeneratorConfig.newInstanceWithCustomizer(c -> c.getDialect()
        .setBindVariableRenderInstance(BindVariableRender.BuiltIn.SPRING_NAMED_PARAMETER));
    SqlGenerator sqlGenerator = new SqlGenerator(config);

    Map<String, Object> params = new HashMap<>();
    params.put("name", "ho%_\\ge");

    String sql = sqlGenerator.generate("""
        /*[# mb:bind='patternName=|${#likes.escapeWildcard(name)}%|' /]*/
        select
            id,
            name
        from
            my_users
        where
            name = /*[# mb:p='patternName']*/ 'Sato' /*[/]*/
        """, params, params::put);

    System.out.println(sql);
    System.out.println(params);
  }
}
select
    id,
    name
from
    my_users
where
    name = :patternName

以下のように、バインド変数paramsnamepatternNameの2つになる。

{patternName=ho\%\_\\ge%, name=ho%_\ge}