Databases 10 min read

Why MyBatis‑Plus Batch Inserts Are Slow and How to Speed Them Up

This article investigates the poor performance of MyBatis‑Plus batch inserts, compares several insertion strategies—including single inserts, saveBatch, manual SQL concatenation, and JDBC executeBatch—measures their execution times, and shows how enabling the rewriteBatchedStatements driver option dramatically improves throughput.

Su San Talks Tech
Su San Talks Tech
Su San Talks Tech
Why MyBatis‑Plus Batch Inserts Are Slow and How to Speed Them Up

Rough Experiment

The author tested four ways of inserting 1,000 rows into a MySQL table and recorded the execution time for each method.

1000 rows inserted one by one
@Test
void MybatisPlusSaveOne() {
    SqlSession sqlSession = sqlSessionFactory.openSession();
    try {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start("mybatis plus save one");
        for (int i = 0; i < 1000; i++) {
            OpenTest openTest = new OpenTest();
            openTest.setA("a" + i);
            openTest.setB("b" + i);
            openTest.setC("c" + i);
            openTest.setD("d" + i);
            openTest.setE("e" + i);
            openTest.setF("f" + i);
            openTest.setG("g" + i);
            openTest.setH("h" + i);
            openTest.setI("i" + i);
            openTest.setJ("j" + i);
            openTest.setK("k" + i);
            // one‑by‑one insert
            openTestService.save(openTest);
        }
        sqlSession.commit();
        stopWatch.stop();
        log.info("mybatis plus save one:" + stopWatch.getTotalTimeMillis());
    } finally {
        sqlSession.close();
    }
}

Result: 121,011 ms.

1000 rows inserted with MyBatis‑Plus saveBatch
@Test
void MybatisPlusSaveBatch() {
    SqlSession sqlSession = sqlSessionFactory.openSession();
    try {
        List<OpenTest> openTestList = new ArrayList<>();
        for (int i = 0; i < 1000; i++) {
            OpenTest openTest = new OpenTest();
            openTest.setA("a" + i);
            openTest.setB("b" + i);
            openTest.setC("c" + i);
            openTest.setD("d" + i);
            openTest.setE("e" + i);
            openTest.setF("f" + i);
            openTest.setG("g" + i);
            openTest.setH("h" + i);
            openTest.setI("i" + i);
            openTest.setJ("j" + i);
            openTest.setK("k" + i);
            openTestList.add(openTest);
        }
        StopWatch stopWatch = new StopWatch();
        stopWatch.start("mybatis plus save batch");
        // batch insert
        openTestService.saveBatch(openTestList);
        sqlSession.commit();
        stopWatch.stop();
        log.info("mybatis plus save batch:" + stopWatch.getTotalTimeMillis());
    } finally {
        sqlSession.close();
    }
}

Result: 59,927 ms (about twice faster than one‑by‑one).

1000 rows inserted with manual SQL concatenation
@Test
void MapperSaveBatch() {
    SqlSession sqlSession = sqlSessionFactory.openSession();
    try {
        List<OpenTest> openTestList = new ArrayList<>();
        for (int i = 0; i < 1000; i++) {
            OpenTest openTest = new OpenTest();
            openTest.setA("a" + i);
            openTest.setB("b" + i);
            openTest.setC("c" + i);
            openTest.setD("d" + i);
            openTest.setE("e" + i);
            openTest.setF("f" + i);
            openTest.setG("g" + i);
            openTest.setH("h" + i);
            openTest.setI("i" + i);
            openTest.setJ("j" + i);
            openTest.setK("k" + i);
            openTestList.add(openTest);
        }
        StopWatch stopWatch = new StopWatch();
        stopWatch.start("mapper save batch");
        // manual batch insert
        openTestMapper.saveBatch(openTestList);
        sqlSession.commit();
        stopWatch.stop();
        log.info("mapper save batch:" + stopWatch.getTotalTimeMillis());
    } finally {
        sqlSession.close();
    }
}

Result: 2,275 ms – 26× faster than MyBatis‑Plus saveBatch.

1000 rows inserted with JDBC executeBatch
@Test
void JDBCSaveBatch() throws SQLException {
    SqlSession sqlSession = sqlSessionFactory.openSession();
    Connection connection = sqlSession.getConnection();
    connection.setAutoCommit(false);

    String sql = "insert into open_test(a,b,c,d,e,f,g,h,i,j,k) values(?,?,?,?,?,?,?,?,?,?,?)";
    PreparedStatement statement = connection.prepareStatement(sql);
    try {
        for (int i = 0; i < 1000; i++) {
            statement.setString(1, "a" + i);
            statement.setString(2, "b" + i);
            statement.setString(3, "c" + i);
            statement.setString(4, "d" + i);
            statement.setString(5, "e" + i);
            statement.setString(6, "f" + i);
            statement.setString(7, "g" + i);
            statement.setString(8, "h" + i);
            statement.setString(9, "i" + i);
            statement.setString(10, "j" + i);
            statement.setString(11, "k" + i);
            statement.addBatch();
        }
        StopWatch stopWatch = new StopWatch();
        stopWatch.start("JDBC save batch");
        statement.executeBatch();
        connection.commit();
        stopWatch.stop();
        log.info("JDBC save batch:" + stopWatch.getTotalTimeMillis());
    } finally {
        statement.close();
        sqlSession.close();
    }
}

Result: 55,663 ms, similar to MyBatis‑Plus saveBatch because both ultimately use the same driver.

After discovering the MySQL driver property rewriteBatchedStatements, the author added it to the JDBC URL (e.g., jdbc:mysql://host/db?rewriteBatchedStatements=true). With this flag enabled, the performance of MyBatis‑Plus saveBatch improved dramatically, dropping to 2,589 ms, comparable to manual SQL concatenation. JDBC executeBatch also fell to 324 ms.

The driver rewrites a batch of individual INSERT statements into a single multi‑value statement like INSERT INTO xxx VALUES (a),(b),(c)…, which explains the speed gain.

Conclusion

For Java applications that rely on JDBC batch operations, enabling rewriteBatchedStatements=true can increase insert throughput by an order of magnitude. When manual SQL concatenation is used, keep the batch size reasonable and split large batches to avoid memory pressure.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

performanceJDBCrewriteBatchedStatementsbatch-insert
Su San Talks Tech
Written by

Su San Talks Tech

Su San, former staff at several leading tech companies, is a top creator on Juejin and a premium creator on CSDN, and runs the free coding practice site www.susan.net.cn.

0 followers
Reader feedback

How this landed with the community

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.