Spring Bootアプリケーション内でDBアクセス処理を含む場合に、MyBatisフレームワークを利用することがあるが、foreach要素を用いることで、引数のリストからIN句を自動生成することができる。
今回は、MyBatisフレームワーク内で引数のリストからIN句を自動生成するサンプルプログラムを作成してみたので、共有する。
前提条件
下記記事の実装が完了していること。
また、Oracle XEのインストールが完了し、USER_DATAテーブルに以下のデータが追加されていること。
1 | select * from USER_DATA order by ID asc |
サンプルプログラムの作成
作成したサンプルプログラムの構成は以下の通り。
なお、上記の赤枠は、前提条件のプログラムから追加/変更したプログラムである。
build.gradleの内容は以下の通りで、Oracle JDBCドライバやMyBatisフレームワーク、Lombokを追加している。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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ログ出力定義を設定している。
1 2 3 4 5 6 7 8 9 | 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句を指定しないよう設定している。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | <?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テーブルのデータを格納するエンティティクラスの内容は以下の通り。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | 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が実行されるようになっている。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | 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句を自動生成することができる。