こちらのページで使い方を把握した MyBatis を、こちらのページで使い方を把握した Spring Boot で利用するための基本的な設定およびサンプルコードをまとめます。サンプルコードにおいては、特に MySQL を対象とします。
公式の解説動画
基本的な Gradle プロジェクトです。
.
|-- build.gradle
|-- gradle
| `-- wrapper
| |-- gradle-wrapper.jar
| `-- gradle-wrapper.properties
|-- gradlew
|-- gradlew.bat
`-- src
`-- main
|-- java
| `-- hello
| |-- Application.java
| |-- City.java
| |-- CityMapper.java
| `-- HelloController.java
`-- resources
|-- application.yml
|-- data.sql
`-- schema.sql
build.gradle
org.mybatis.spring.boot:mybatis-spring-boot-starter
のバージョンは spring-boot-gradle-plugin
によって自動解決されないため、こちらのページをもとに調べて指定する必要があります。今回は 1.3.0 を利用します。
buildscript {
ext {
springBootVersion = '1.5.3.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'
jar {
baseName = 'gs-spring-boot'
version = '0.1.0'
}
repositories {
mavenCentral()
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
dependencies {
compile('org.springframework.boot:spring-boot-starter-web')
compile('mysql:mysql-connector-java:6.0.6')
// 以下のページをもとにバージョンを指定します。
// http://www.mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/
// http://search.maven.org/#artifactdetails|org.mybatis.spring.boot|mybatis-spring-boot-starter|1.3.0|jar
compile('org.mybatis.spring.boot:mybatis-spring-boot-starter:1.3.0')
}
src/main/resources/application.yml
MySQL DB 接続情報を設定します。
spring:
datasource:
url: jdbc:mysql://localhost:3306/mydb
username: myuser
password: myuser
driver-class-name: com.mysql.jdbc.Driver
src/main/resources/{schema|data}.sql
出力先 MySQL テーブルの DDL および DML です。こちらのページに記載されているとおり、schema.sql および data.sql というファイル名の SQL がアプリケーション起動時に実行されます。より柔軟かつ高度な初期化処理が必要な場合は Flyway と連携するように設定します。
schema.sql
DROP TABLE IF EXISTS city;
CREATE TABLE city (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255),
state VARCHAR(255),
country VARCHAR(255)
);
data.sql
INSERT INTO city (name, state, country) VALUES ('San Francisco', 'CA', 'US');
src/main/java/hello/Application.java
アノテーションの意味については、こちらをご参照ください。
package hello;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
src/main/java/hello/City.java
Getter/Setter が定義されたドメインクラスです。Lombok の @Data
などを利用すると簡潔な記述が可能になりますが、今回は使用していません。
package hello;
public class City {
private Long id;
private String name;
private String state;
private String country;
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public String getState() {
return this.state;
}
public void setState(String state) {
this.state = state;
}
public String getCountry() {
return this.country;
}
public void setCountry(String country) {
this.country = country;
}
@Override
public String toString() {
return getId() + "," + getName() + "," + getState() + "," + getCountry();
}
}
src/main/java/hello/CityMapper.java
@Param
アノテーションは、今回のようにパラメータが一つの場合は指定しなくても問題ありませんが、複数パラメータが存在する場合は SQL クエリ内のパラメータとメソッド引数の対応関係を設定するために指定する必要があります。また、ここでは @Select
アノテーションで SQL を設定していますが、より柔軟な設定を行うためには後述の XML ファイルを利用します。
package hello;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
@Mapper
public interface CityMapper {
@Select("SELECT id, name, state, country FROM city WHERE state = #{state}")
City findByState(@Param("state") String state);
}
src/main/java/hello/HelloController.java
cityMapper.findByState()
および sqlSession.selectOne()
を利用する例です。実際にはコントローラ内で直接利用するのではなく、@Service や @Repository を設定したクラス内で利用します。
package hello;
import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HelloController {
@Autowired
private CityMapper cityMapper;
@Autowired
private SqlSession sqlSession;
@RequestMapping("/")
public String index() {
City city1 = cityMapper.findByState("CA");
City city2 = sqlSession.selectOne("hello.CityMapper.findByState", "CA");
System.out.println(city1);
System.out.println(city2);
return "Greetings from Spring Boot!";
}
}
サンプルプロジェクトにおいて、アノテーションで設定していた箇所を XML ファイルに置き換えると以下のようになります。
src/main/java/hello/CityMapper.java
package hello;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
//import org.apache.ibatis.annotations.Select;
@Mapper
public interface CityMapper {
// @Select("SELECT id, name, state, country FROM city WHERE state = #{state}")
City findByState(@Param("state") String state);
}
src/main/resources/hello/CityMapper.xml
<?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="hello.CityMapper">
<select id="findByState" resultType="hello.City">
SELECT * FROM city WHERE state = #{state}
</select>
</mapper>
凡例
<?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="hello.CityMapper">
[[SQL 設定がここに入ります]]
</mapper>
適宜 @Param
設定を設定してください。返り値も適宜 List<City>
に変更してください。
package hello;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@Mapper
public interface CityMapper {
City findByState(@Param("name") String name, @Param("state") String state);
}
<select id="findByState" resultType="hello.City">
SELECT * FROM city WHERE name LIKE #{name}
<if test="state != null">
AND state = #{state}
</if>
</select>
いずれか一つだけ選択されます。switch-case 文のようなものです。
<select id="findByState" resultType="hello.City">
SELECT * FROM city WHERE
<choose>
<when test="name != null">
name = #{name}
</when>
<when test="state != null">
state = #{state}
</when>
<otherwise>
country = 'mycountry'
</otherwise>
</choose>
</select>
where
を利用すると、条件に一つも合致しない場合は何も挿入されず、合致した最初の条件が AND や OR から始まる場合は取り除かれます。以下の例で name も state も指定しないと city が全件返されます。state だけ指定すると AND が削除されて WHERE 句が挿入されます。
<select id="findByState" resultType="hello.City">
SELECT * FROM city
<where>
<if test="name != null">
name = #{name}
</if>
<if test="state != null">
AND state = #{state}
</if>
</where>
</select>
where
のような機能をカスタマイズして実現したい場合は trim
を利用します。where
のサンプルコードを trim
で記述すると以下のようになります。
<select id="findByState" resultType="hello.City">
SELECT * FROM city
<trim prefix="WHERE" prefixOverrides="AND |OR ">
<if test="name != null">
name = #{name}
</if>
<if test="state != null">
AND state = #{state}
</if>
</trim>
</select>
UPDATE 文について、set
を利用すると合致した最後の条件が ,
で終わる場合は取り除かれます。where
の場合と同様に trim
で同等の機能を実現できます。
<update id="findByState">
UPDATE city
<set>
<if test="name != null">name=#{name},</if>
<if test="state != null">state=#{state}</if>
</set>
WHERE country = 'US'
</update>
<select id="findByState" resultType="hello.City">
SELECT * FROM city WHERE name IN
<foreach item="name" index="index" collection="names" open="(" separator="," close=")">
#{name}
</foreach>
</select>
一時変数を定義できます。引数も参照できます。
<select id="findByState" resultType="hello.City">
<bind name="pattern" value="'%' + name + '%'" />
SELECT * FROM city WHERE name LIKE #{pattern}
</select>
ここまでのサンプルで利用してきた、独自に定義した City 以外にも、基本的な resultType
が予め用意されています。例えば hashmap
を利用すると以下のようになります。