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.
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.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
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.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
