SpringBootとMyBatisを連携するための設定方法

8 min読了の目安(約7300字TECH技術記事

はじめに

開いていただきありがとうございます。
数週間前にVScodeでSpringBoot + MyBatisプロジェクトを作成するという記事を作成しました。
上記の内容ではプロジェクトを作成することを目的としていたため、springとMyBatis連携の詳細な内容まで書きませんでした。
なので、本記事ではspringとMyBatisを連携させる方法を書いていきたいと思います。

作業環境

  • macOS Catalina バージョン 10.15.5
  • OpenJDK 11.0.9.1
  • Visual Studio Code
  • DB:SQLite3
    ※VScodeでのSpringBootプロジェクトの作成方法は以下の記事の「DBの追加」までを参考にしていただければと思います。

https://zenn.dev/s_t_pool/articles/486dfaa7c2e5fb7a6a03

SpringとMyBatisを連携させるための設定

SpringとMyBatisを連携するためのポイントは以下の通りです。

  • Mapperインターフェースのスキャン機能を有効にします。
  • SpringのDIコンテナに、データソースのBeanを登録します。
  • SpringのDIコンテナにSqlSessionFactoryのBeanを登録します。
  • SpringのDIコンテナに、トランザクションマネージャーのBeanを登録します。
  • アノテーション駆動(@Transactional)のトランザクション制御を有効にします。

SpringとMyBatisを連携するためのBean定義例は以下の通りです。

package com.example.demo.config;

import javax.sql.DataSource;

import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
// @org.springframework.transaction.annotation.EnableTransactionManagementを付与し、
// アノテーション駆動(@Transactional)のトランザクション制御を有効にします。
@EnableTransactionManagement
// @org.mybatis.spring.annotation.MapperScanを付与し、Mapperインターフェースのスキャンを有効にします。
@MapperScan("com.example.demo.mapper")
public class MyBatisConfig {

    // データソースのBean定義をします。
    // 今回はSQLite3を使用するため、DBファイルのパスを指定します。
    @Bean
    public DataSource dataSource() {
        return DataSourceBuilder.create().url("jdbc:sqlite:demo/db/database2.sqlite3").build();
    }

    // org.mybatis.spring.SqlSessionFactoryBeanをBean定義します。
    // これによりSqlSessionFactoryBeanを利用してSqlSessionFactoryが生成されます。
    @Bean
    public SqlSessionFactoryBean sqlSessionFactory() {
        SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
        // データソースを設定する。MyBatisの処理の中でSQLを発行すると、
        // ここで指定したデータソースからコネクションが取得されます。
        sessionFactoryBean.setDataSource(dataSource());
        // MyBatis設定ファイルを指定します。
        // 今回はresources直下に設定ファイルを配置します。
        sessionFactoryBean.setConfigLocation(new ClassPathResource("/myBatis-config.xml)");
        return sessionFactoryBean;
    }

    // トランザクションマネージャーのBeanを定義します。
    @Bean
    public PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dataSource());
    }
}

MyBatisの設定

MyBatisの設定はMyBatis設定ファイルを使用して行います。
設定ファイルにおける必須項目はありませんが、デフォルトの動作を変更したい場合に設定するようにします。
MyBatisは様々な設定項目があるため、詳細はMyBatisのリファレンスを参照してください。

https://mybatis.org/mybatis-3/ja/configuration.html

今回例として設定する項目は以下の通りです。

  1. NULL値とJDBC型のマッピング設定
    • 使用するDBによってカラム値をnullに設定するとエラーが発生します。これはMyBatisのデフォルト値がJDBC型のOTHER型にマッピングされているためで、JDBCドライバがnull値の設定と認識できるJDBC型を指定することができます。
  2. mapUnderscoreToCamelCase
    • DBにあるアンダースコアを含む列をキャメルケースのJavaプロパティに自動的にマッピングする機能の有効/無効を切り替えます。
  3. TypeAlias
    • マッピングファイルで指定するJavaクラスに対して、エイリアスを割り当てる機能です。
    • 使用しない場合、Javaクラスを完全修飾名で指定する必要があります。

MyBatis設定ファイルの例は以下の通りです。

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <settings>
        <!-- 設定1:NULL値とJDBC型のマッピング設定-->
        <setting name="jdbcTypeForNull" value="NULL"/>
        <!-- 設定2:mapUnderscoreToCamelCase-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
    <!-- 設定3:TypeAlias-->
    <typeAliases>
        <package name="com.example.demo.domain"/>
    </typeAliases>

</configuration>

今回は設定ファイルをresources直下に配置します。

マッパーインターフェースの作成

設定が完了したので実際にDBアクセスするためのマッパーインタフェースを作成していきます。
マッパーインターフェースの例は以下の通りです。

// パッケージは@MapperScanで指定した規定パッケージ配下にします。
// 規定パッケージ配下にしない場合はエラーになります。
package com.example.demo.mapper;

import java.util.List;

import com.example.demo.domain.TestTable;

import org.apache.ibatis.annotations.Mapper;

// マッパーインターフェースは通常のJavaインターフェースとして作成します。
// @org.apache.ibatis.annotations.Mapperを付与し、
// マッパーインターフェースとして読み込ませます。
@Mapper
public interface SampleMapper {
  // 今回は複数の検索結果を返却したいので、java.util.Listに格納して返却します。
  List<TestTable> findAlList();

}

SQL実行結果と戻り値となるオブジェクトをマッピングするdomainクラスの定義は以下の通りです。
(Lombokを使用しています。)

package com.example.demo.domain;

import lombok.Data;

@Data
public class TestTable {
    private String name;
}

マッピングファイルの作成

作成するマッピングファイルのファイル名はマッパーインターフェース.xmlとし、マッパーインターフェースのパッケージと同じ階層のクラスパス上に配置します。
こうすることで、MyBatisが自動でマッピングファイルを読み込んでくれます。
マッピングファイル作成の例は以下の通りです。

<?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">
<!-- namespacce属性にマッパーインターフェースの完全修飾クラス名を指定します。
      ここが存在しない場合起動時にエラーになります。-->
<mapper namespace="com.example.demo.mapper.SampleMapper">
    <select id="findAlList" resultType="TestTable">
        select * from test_table
    </select>
</mapper>

<select>要素のid属性にはマッパーインターフェースに定義したメソッドのメソッド名、resultType属性には検索結果をマッピングするクラス名を指定します。今回はmyBatisの設定ファイルでTypeAliasを設定しているので、Javaクラスを完全修飾名で指定する必要はありません。

最終的な構成は以下の通りです。
構成

DBアクセスしてみる

では実際にDBアクセスを呼び出して値を取得できるか確認してみましょう。
マッパーインターフェースの呼び出すための例は下記の通りです。

package com.example.demo.controller;

import java.util.List;

import com.example.demo.domain.TestTable;
import com.example.demo.mapper.SampleMapper;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class SampleController {
    // マッパーインターフェースをインジェクションします。
    @Autowired
    SampleMapper mapper;

    @RequestMapping("/")
    public String index(Model model) {
      // メソッドを呼びます。
      List<TestTable> resultList = mapper.findAlList();
      // Modelに詰めます。
      model.addAttribute("results", resultList);

      return "index";
    }
}

以下のキャプチャの通りresultListにDBの値が取得できたら成功です。
(デバック起動して変数に意図した値を取得できているかを確認しています。)

最後に・・・

ここまでSpringとMyBatis連携について書いてみました。
今回書いた方法以外にも実現方法はあるみたいなので、最適な方法を今後も探っていこうと思います。

参考