Backend Development 7 min read

Why MyBatis‑Plus saveBatch Is Slow and How to Fix It with JDBC rewriteBatchedStatements

This article explains why using MyBatis‑Plus saveBatch for bulk inserts can cause 5‑6 second delays, analyzes the underlying per‑row INSERT behavior, and shows how adding rewriteBatchedStatements=true to the JDBC URL dramatically reduces execution time to a few hundred milliseconds.

macrozheng
macrozheng
macrozheng
Why MyBatis‑Plus saveBatch Is Slow and How to Fix It with JDBC rewriteBatchedStatements

When developing a backend message‑sending feature with MyBatis‑Plus, the

saveBatch()

method performed well in test but took 5–6 seconds in the pre‑release environment.

MyBatis‑Plus is a popular ORM framework built on MyBatis, offering code generation, generic CRUD, pagination, optimistic lock, and other conveniences.

Reproducing the Issue

<code>@Transactional(rollbackFor = Exception.class)
public boolean saveNotice(Notify notify, String receiveUserIds) {
    long begin = System.currentTimeMillis();
    notify.setCreateTime(new Date());
    notify.setCreateBy(ShiroUtil.getSessionUid());
    if (notify.getPublishTime() == null) {
        notify.setPublishTime(new Date());
    }
    boolean insert = save(notify);
    List<NotifyRecord> collect = new ArrayList<>();
    List<String> receiveUserList = fillNotifyRecordList(notify, receiveUserIds, collect);
    notifyRecordService.saveBatch(collect);
    long end = System.currentTimeMillis();
    System.out.println(end - begin);
    return insert;
}

public List<String> fillNotifyRecordList(Notify notify, String receiveUserIds, List<NotifyRecord> collect) {
    List<String> noticeRecordList = new ArrayList<>(200);
    // assemble 200 user notification records
    return noticeRecordList;
}</code>

The method saves a notification, assembles 200 user notification records, and calls

saveBatch()

to persist them.

Save the notification message.

Assemble a list of 200 user notification records.

Batch save the records.

Testing shows the first two steps are fast; the third step is slow. The SQL log reveals each INSERT takes several seconds:

<code>-- slow sql 5542 millis. INSERT INTO oa_notify_record (notifyId, receiveUserId, receiveUserName, isRead, createTime) VALUES (?, ?, ?, ?, ?)</code>

MyBatis‑Plus implements

saveBatch()

by iterating over the collection and executing a separate INSERT for each entity, which explains the high latency.

The MyBatis Log Free plugin can automatically print the full SQL statements in the console.

Solution

Adding the parameter

rewriteBatchedStatements=true

to the JDBC URL enables the MySQL driver to rewrite batch operations into a single multi‑row INSERT, dramatically improving performance.

By default, the MySQL JDBC driver splits executeBatch() into individual statements; only with rewriteBatchedStatements=true (driver version 5.1.13 or newer) does it execute true batch inserts, which also benefits UPDATE and DELETE statements.

After updating the JDBC URL, the batch insert time dropped from several seconds to about 200 ms, effectively resolving the performance issue of MyBatis‑Plus

saveBatch()

.

performanceJDBCMyBatis-Plusbatch insertrewriteBatchedStatementssaveBatch
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.