Spring Boot DB連携

MyBatisフレームワーク内で引数のリストからIN句を自動生成してみた

Spring Bootアプリケーション内でDBアクセス処理を含む場合に、MyBatisフレームワークを利用することがあるが、foreach要素を用いることで、引数のリストからIN句を自動生成することができる。

今回は、MyBatisフレームワーク内で引数のリストからIN句を自動生成するサンプルプログラムを作成してみたので、共有する。

前提条件

下記記事の実装が完了していること。

IntelliJ IDEA上でGradleを使ってWeb画面のSpring Bootプロジェクトを作成してみたSpring Bootのプロジェクトを新規作成を「IntelliJ IDEA」のメニューから実施しようとしたところ、無料の「Commun...

また、Oracle XEのインストールが完了し、USER_DATAテーブルに以下のデータが追加されていること。

select * from USER_DATA order by ID asc
前提条件

サンプルプログラムの作成

作成したサンプルプログラムの構成は以下の通り。
サンプルプログラムの構成
なお、上記の赤枠は、前提条件のプログラムから追加/変更したプログラムである。

build.gradleの内容は以下の通りで、Oracle JDBCドライバやMyBatisフレームワーク、Lombokを追加している。

plugins {
	id 'org.springframework.boot' version '2.1.7.RELEASE'
	id 'java'
}

apply plugin: 'io.spring.dependency-management'

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

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    compileOnly 'org.projectlombok:lombok:1.18.10'
    annotationProcessor 'org.projectlombok:lombok:1.18.10'
    compile files('lib/ojdbc6.jar')
    implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.1.1'
}

また、application.propertiesの内容は以下の通りで、DB接続先やSQLログ出力定義を設定している。

server.port = 8084
# DB接続先
spring.datasource.url=jdbc:oracle:thin:@localhost:1521:xe
spring.datasource.username=USER01
spring.datasource.password=USER01
spring.datasource.driverClassName=oracle.jdbc.driver.OracleDriver
# SQLログ出力
logging.level.org.springframework=warn
logging.level.com.example.demo.UserDataMapper=debug



さらに、UserDataMapper.java、UserDataMapper.xmlの内容は以下の通りで、UserDataMapper.xml内で、foreach要素内で引数のリストからIN句を自動生成している。なお、引数のリストがNULLか空の場合は、WHERE句を指定しないよう設定している。

package com.example.demo;

import org.apache.ibatis.annotations.Mapper;
import java.util.ArrayList;

@Mapper
public interface UserDataMapper {

    /**
     * 指定したIDリストをもつユーザーデータテーブル(user_data)のデータを取得する
     * @param idList IDリスト
     * @return ユーザーデータテーブル(user_data)の指定したIDリストのデータ
     */
    ArrayList<UserData> findByIdList(ArrayList<Long> idList);
}
<?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="findByIdList" parameterType="java.util.List" resultType="com.example.demo.UserData">
        SELECT
              id
            , name
            , birth_year as birthY
            , birth_month as birthM
            , birth_day as birthD
            , sex
            , CASE sex
              WHEN '1' THEN '男'
              WHEN '2' THEN '女'
              ELSE ''
              END AS sex_value
        FROM USER_DATA
        <where>
            <if test="list != null and list.size() > 0">
                id in
                <foreach item="item" open="(" close=")" collection="list" separator=",">
                    #{item}
                </foreach>
            </if>
        </where>
    </select>
</mapper>

また、USER_DATAテーブルのデータを格納するエンティティクラスの内容は以下の通り。

package com.example.demo;

import lombok.Data;

/**
 * ユーザーデータテーブル(user_data)アクセス用エンティティ
 */
@Data
public class UserData {

    /** ID */
    private long id;

    /** 名前 */
    private String name;

    /** 生年月日_年 */
    private int birthY;

    /** 生年月日_月 */
    private int birthM;

    /** 生年月日_日 */
    private int birthD;

    /** 性別 */
    private String sex;

    /** 性別(文字列) */
    private String sex_value;

}

さらに、Spring Bootのメインクラスの内容は以下の通りで、CommandLineRunnerインタフェースを実装しrunメソッド内でMapper呼出処理を記載することで、このクラスを起動しただけでMapper内のSQLが実行されるようになっている。

package com.example.demo;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import java.util.ArrayList;

@SpringBootApplication
public class DemoApplication implements CommandLineRunner {

    @Autowired
    private UserDataMapper userDataMapper;

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Override
    public void run(String... args) {
	    // IN句を指定したSQLの実行結果を確認する
        // 引数のIDリストに1件以上のデータを指定した場合
        ArrayList<UserData> userDataList = userDataMapper.findByIdList(getIdListOverOne());
        System.out.println("*** 引数のIDリストに1件以上のデータを指定した場合 ***");
        System.out.println("userDataList : " + userDataList);
        System.out.println();

        // 引数のIDリストにnullを指定した場合
        userDataList = userDataMapper.findByIdList(null);
        System.out.println("*** 引数のIDリストにnullを指定した場合 ***");
        System.out.println("userDataList : " + userDataList);
        System.out.println();

        // 引数のIDリストに空リストを指定した場合
        ArrayList<Long> idList = new ArrayList<>();
        userDataList = userDataMapper.findByIdList(idList);
        System.out.println("*** 引数のIDリストに空リストを指定した場合 ***");
        System.out.println("userDataList : " + userDataList);
    }

    private ArrayList<Long> getIdListOverOne(){
        ArrayList<Long> idList = new ArrayList<>();
        idList.add(Long.valueOf(1));
        idList.add(Long.valueOf(2));
        idList.add(Long.valueOf(3));
	    return idList;
    }
}



サンプルプログラムの実行結果

Spring Bootのメインクラス(DemoApplication.java)を実行した結果、コンソールログに出力される内容は以下の通り。
サンプルプログラムの実行結果
上記実行結果の赤枠部分で、UserDataMapperクラスのfindByIdListメソッドの引数に指定したリストからIN句が自動生成されることが、青枠・緑枠部分で、UserDataMapperクラスのfindByIdListメソッドの引数にNULLや空文字を指定した場合にWHERE句が設定されないことが、それぞれ確認できる。

要点まとめ

  • MyBatisフレームワーク内でforeach要素を用いることで、引数のリストからIN句を自動生成することができる。