SQLのバッチ実行
大量にUPDATE, DELETE, INSERTする場合JDBCのバッチ実行機能を使用しないとパフォーマンスが悪化する。
バッチ実行でなくとも、INSERTはまとめて実行できるし、DELETEはWHERE句でINを使って絞ることできれば一度の実行で済むことも多い。ただ複数のUPDATEを一度のSQL実行で済ますことは難しいことが多い。
MyBatisでもExecutorType.BATCH
を設定したSqlSession
を利用することでバッチ処理ができる。
MyBatisの通常の実行モード
ただ通常アプリ内でバッチ実行する箇所は限られているため、SpringにDIさせるSqlSessionはデフォルトの実行モードのものにするのが普通。
Spring Bootで特に設定をしなければ、UserMapperはデフォルトのExecutorType.SIMPLE
を使い、ステートメントを実行するたびに新しいPreparedStatementを作成するようになっている。
@Autowired
UserMapper userMapper;
public void insert() {
userMapper.insert(user);
}
バッチモードに変更する
特定の処理クラスでバッチ実行に変更したい場合、ExecutorType.BATCH
を設定したSqlSessionTemplate
が注入されたMapperクラスを取得する必要がある。
Spring BootのJava ConfigでそのようなSqlSessionTemplate
を取得できるように設定を書き、そのSqlSessionTemplate
が注入される専用のMapperクラスを用意することもできるが、バッチ実行する箇所が1, 2箇所と限られている場合はその場所だけでアドホックにSqlSessionFactory
からExecutorType.BATCH
を設定したSqlSessionTemplate
を生成するのが簡単。
@Service
public class BatchService {
private final SqlSession sqlSession;
public BatchService(@Autowired SqlSessionFactory sqlSessionFactory) {
this.sqlSession = new SqlSessionTemplate(sqlSessionFactory, ExecutorType.BATCH);
}
@Transactional
public void insertBatch() {
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
int count = 0;
int size = users.size();
for (var user : users) {
count++;
userMapper.insert(user);
// 1000件ごとと最後にフラッシュ
if (count % 1000 == 0 || count == size) {
sqlSession.flushStatements();
}
}
}
}
動作確認version
- Java11
- Spring Boot 2.2
- MyBatis 3.5.3
- MySQL8