MyBatis | バッチ更新

デフォルトでは、SQLを実行するたびにPreparedStatementを作成し、SQLをデータベースへ送信している。

更新件数が多い場合、これは非常に効率が悪い。

MyBatisでは設定により、PreparedStatementの再利用とバッチ更新が可能である。

基本動作

ソースコード

sample_mapper.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="sample.mybatis">

  <insert id="insertTest">
    insert into test_table (value) values (#{value})
  </insert>
</mapper>

Main.java

package sample.mybatis;

import java.io.InputStream;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class Main {

    public static void main(String[] args) throws Exception {
        try (InputStream in = Main.class.getResourceAsStream("/mybatis-config.xml")) {
            SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);

            try (SqlSession session = factory.openSession()) {
                for (int i=0; i<3; i++) {
                    TestTable t = new TestTable("value-" + i);
                    int updateCount = session.insert("sample.mybatis.insertTest", t);
                    System.out.println("updateCount = " + updateCount);
                }

                session.commit();
            }
        }
    }
}
  • 3回繰り返してINSERTを実行するように実装している。

実行結果

[DEBUG] s.m.insertTest  - ==>  Preparing: insert into test_table (value) values (?) 
[DEBUG] s.m.insertTest  - ==> Parameters: value-0(String)
[DEBUG] s.m.insertTest  - <==    Updates: 1
updateCount = 1
[DEBUG] s.m.insertTest  - ==>  Preparing: insert into test_table (value) values (?) 
[DEBUG] s.m.insertTest  - ==> Parameters: value-1(String)
[DEBUG] s.m.insertTest  - <==    Updates: 1
updateCount = 1
[DEBUG] s.m.insertTest  - ==>  Preparing: insert into test_table (value) values (?) 
[DEBUG] s.m.insertTest  - ==> Parameters: value-2(String)
[DEBUG] s.m.insertTest  - <==    Updates: 1
updateCount = 1

説明

  • 毎回PreparedStatementが作成され、SQLが送信されている。

PreparedStatementを再利用する

ソースコード

mybatis-config.xml

<?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>
    <setting name="defaultExecutorType" value="REUSE"/>
  </settings>

  ...
</configuration>

実行結果

[DEBUG] s.m.insertTest  - ==>  Preparing: insert into test_table (value) values (?) 
[DEBUG] s.m.insertTest  - ==> Parameters: value-0(String)
[DEBUG] s.m.insertTest  - <==    Updates: 1
updateCount = 1
[DEBUG] s.m.insertTest  - ==> Parameters: value-1(String)
[DEBUG] s.m.insertTest  - <==    Updates: 1
updateCount = 1
[DEBUG] s.m.insertTest  - ==> Parameters: value-2(String)
[DEBUG] s.m.insertTest  - <==    Updates: 1
updateCount = 1

説明

  • 設定ファイルでdefaultExecutorTypeREUSEを設定する。
  • PreparedStatementは1回だけ作成される。
  • SQLの送信は毎回行われている。

バッチ実行

ソースコード

mybatis-config.xml

<?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>
    <setting name="defaultExecutorType" value="BATCH"/>
  </settings>

  ...
</configuration>

実行結果

[DEBUG] s.m.insertTest  - ==>  Preparing: insert into test_table (value) values (?) 
[DEBUG] s.m.insertTest  - ==> Parameters: value-0(String)
updateCount = -2147482646
[DEBUG] s.m.insertTest  - ==> Parameters: value-1(String)
updateCount = -2147482646
[DEBUG] s.m.insertTest  - ==> Parameters: value-2(String)
updateCount = -2147482646

説明

  • defaultExecutorTypeBATCHにすると、一括更新される。
  • SQLの送信は最後にまとめて行われる。
  • そのため、更新件数は取得できない。

SqlSessionを取得するときに指定する

バッチ更新するかどうかの設定は、SqlSessionを取得するときの引数で指定できる。

import org.apache.ibatis.session.ExecutorType;

...

SqlSession session = factory.openSession(ExecutorType.BATCH);

openSession()の引数にExecutorTypeを渡して指定できる。 ここで指定した条件は設定ファイルより優先される。