MyBatis Spring-Boot-Starter(MyBatis Integration with Spring Boot)について
1. 本記事で利用した技術のVersion
- openjdk 11.0.9
- mybatis-spring-boot-starter 2.2.0
- PostgreSQL 13.1
2. MyBatis Spring Boot Starter GitHub
3. 公式 MyBatis document
MyBatis
https://mybatis.org/mybatis-3/ja/index.html
MyBatis-Spring
https://mybatis.org/spring/ja/index.html
MyBatis Spring-boot-starter
http://www.mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure
4. この記事の参考用GitHub
https://github.com/sakuoden/mybatis-sample
5. MyBatis Spring-Boot-Starter概要
MyBatis単体でMapperを使うまでの手順
本来MyBatisを利用してMapperを利用するまでの手順は下記の通りである。
String resource = "org/mybatis/example/mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream); try (SqlSession session = sqlSessionFactory.openSession()) { BlogMapper mapper = session.getMapper(BlogMapper.class); Blog blog = mapper.selectBlog(101); }
- 設定xmlファイルを読み込んで
SqlSessionFactory
を生成する。 SqlSessionFactory
によりSqlSession
を開く。SqlSession
のgetMapperメソッドでMapperを取得する。- Mapperで作成したメソッドを利用する。
MyBatis Spring単体でMapperを使うまでの手順
@Configuration public class MyBatisConfig { @Bean public DataSource dataSource() { return DataSourceBuilder.create().type(HikariDataSource.class).build(); } @Bean public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception { SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean(); factoryBean.setDataSource(dataSource); return factoryBean.getObject(); } }
try (SqlSession session = sqlSessionFactory.openSession()) { BlogMapper mapper = session.getMapper(BlogMapper.class); Blog blog = mapper.selectBlog(101); }
- DataSourceのBeanを登録する。
- SqlSessionFactoryのBeanを登録する。
- 利用したい箇所で登録したSqlSessionFacotryのBeanをInjectionする。
MyBatis Spring-Boot-Starterは...?
上記のようなDataSourceのBean登録やSqlSessionFactoryのBean登録などをSpring Bootが自動で行なってくれる。
6. 必要なライブラリのインストール
dependencies { implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:?.?.? runtimeOnly 'org.postgresql:postgresql' }
org.mybatis.spring.boot:mybatis-spring-boot-starter
上記の?.?.?
は自身でversionを記述する。
利用できるversionはMaven Repositoryを参照すると良い。
本記事ではMyBatis Spring-Boot-Starter 2.2.0を利用するため下記のような記述になる。
dependencies { implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.2.0 runtimeOnly 'org.postgresql:postgresql' }
org.postgresql:postgresql
このライブラリは、PostgreSQLに接続するためのJDBCである。
参考実装
7. build対象の設定
gradleのjavaプラグインのデフォルトだと、src/main/java
配下に配置するxmlファイルをbuildしない。
gradleのjavaプラグインは、src/main/java
のjavaファイルのみを読み取るためである。
見通しを良くする目的でHogeMapper.javaファイルと同じディレクトリにHogeMapper.xmlファイルを配置すると、上記の理由からHogeMapper.xmlはbuildされない。
結果として、HogeMapper.javaファイルと同じディレクトリにHogeMapper.xmlファイルを配置するとHogeMapper.xmlファイルは存在するのにbuild先には存在しないため下記のエラーが出る。
Invalid bound statement (not found): jtn.sample.user.UserMapper.insert org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): jtn.sample.user.UserMapper.insert
これの解決策としてsrc/main/java
配下のxmlファイルをbuild先のresourcesディレクトリにbuildするようにする。
これにより、MyBatisがxmlファイルを読み込めるようになり、後述するMapper.xmlファイルを読み込めるようになる。
このbuild.gradleの設定が下記である。
sourceSets { main { resources.srcDirs = ['src/main/java', 'src/main/resources'] } }
参考実装
https://github.com/sakuoden/mybatis-sample/blob/main/build.gradle#L11-L15
参考記事
8. DataSourceの設定
application.properties
application.propertiesにDataSourceのオブジェクトの値を記述する。
基本的には下記の4点を設定すれば良い。
- driver-class-name
- url
- username
- password
参考記事
9. Mapper Interfaceの作成
@Mapper public interface DentalClinicMapper { void insert(@Param("dentalClinic") DentalClinic dentalClinic); Optional<DentalClinic> find(@Param("clinicNumber") ClinicNumber clinicNumber); }
10. MapperXMLの作成
MapperXMLの基本テンプレート
<?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="●●●.●●●Mapper"> </mapper>
下記のmapperタグ内にMapperの構文を書く。
●●●.●●●Mapperには、上記の9で作成したMapper interfaceの完全修飾クラス名を記載する。
11. Selectしたデータベースの情報をJavaオブジェクトのインスタンスにMappingする
クラス設計
public class DentalClinic { ClinicNumber clinicNumber; ClinicName clinicName; DentalClinic() {} }
public class ClinicNumber { String value; ClinicNumber() {} }
public class ClinicName { String value; public ClinicName() {} public ClinicName(String clinicName) { this.value = clinicName; } }
上記のDentalClinicクラスの通り、MyBatisでMappingするオブジェクトのクラスは、デフォルトコンストラクタを持つ必要がある。
ClinicNumber, ClinicNameクラスの通り、そのオブジェクトのクラスが持つオブジェクトのクラスも同様である。
ResultMapを利用しない書き方
<select id="find" resultType="jtn.sample.dentalclinic.DentalClinic"> SELECT dental_clinics.clinic_number AS "clinicNumber.value", dental_clinics.clinic_name AS "clinicName.value" FROM dental_clinics WHERE dental_clinics.clinic_number = #{clinicNumber.value} </select>
idには、Mapper Interfaceで定義したメソッド名を記述する。
resultTypeには、マッピングする対象のオブジェクトの完全修飾クラス名を定義する。
SELECTのカラム名に、マッピングする対象のオブジェクトのfieldの変数名を AS
を利用して名づける。fieldの型がプリミティブじゃない場合、プリミティブな型にたどり着くまで .
でチェーンする。
ResultMapを利用する書き方
<resultMap id="DentalClinic" type="jtn.sample.dentalclinic.DentalClinic"> <id property="clinicNumber.value" column="clinic_number"/> <result property="clinicName.value" column="clinic_name"/> </resultMap> <select id="find" resultMap="DentalClinic"> SELECT dental_clinics.clinic_number, dental_clinics.clinic_name FROM dental_clinics WHERE dental_clinics.clinic_number = #{clinicNumber.value} </select>
resultMapのidには、ResultMapを識別するIdentityを記述する。
resultMapのTypeには、マッピングする対象のオブジェクトの完全修飾クラス名を定義する。
resultMapタグの配下のid
タグは、マッピングする対象のオブジェクトのIdentityに該当するものに対して使用する。それ以外にはresult
タグを使用する。
.
でチェーンする。