Databases 8 min read

Optimizing MyBatis Batch Inserts: Reducing CPU Usage and Improving Performance

The article explains why MyBatis foreach‑based batch inserts can cause extreme CPU usage and long execution times, demonstrates how combining multiple VALUES into a single INSERT or using ExecutorType.BATCH dramatically improves performance, and provides practical code examples and sizing recommendations.

Java Captain
Java Captain
Java Captain
Optimizing MyBatis Batch Inserts: Reducing CPU Usage and Improving Performance

In a recent project a long‑running job consumed excessive CPU because the bulk of the time was spent on batch inserting data with MyBatis using a <foreach> loop.

The typical mapper configuration looks like this:

<insert id="batchInsert" parameterType="java.util.List">
    insert into USER (id, name) values
    <foreach collection="list" item="model" index="index" separator=",">
        (#{model.id}, #{model.name})
    </foreach>
</insert>

The performance gain comes from converting many single‑row INSERT statements into a single multi‑row INSERT, e.g.:

INSERT INTO `table1` (`field1`, `field2`) VALUES
    ("data1", "data2"),
    ("data1", "data2"),
    ("data1", "data2"),
    ("data1", "data2"),
    ("data1", "data2");

MySQL documentation confirms that grouping many small operations into one large statement can reduce the number of index updates and consistency checks, but it also warns that the statement should not become too large; otherwise it may hit parameter limits or cause parsing overhead.

When using <foreach> with thousands of values (e.g., 5000+), the generated PreparedStatement becomes extremely long, causing exponential growth in parsing time because MyBatis must evaluate the foreach part and build parameter mappings for every execution.

Practical experience shows that limiting each INSERT to about 20‑50 rows keeps the execution time acceptable; larger batches lead to unacceptable delays.

MyBatis itself recommends a different batch‑insert approach by setting the session executor to ExecutorType.BATCH and issuing many small inserts, for example:

SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH);
try {
    SimpleTableMapper mapper = session.getMapper(SimpleTableMapper.class);
    List<SimpleTableRecord> records = getRecordsToInsert();
    BatchInsert<SimpleTableRecord> batchInsert = insert(records)
        .into(simpleTable)
        .map(id).toProperty("id")
        .map(firstName).toProperty("firstName")
        .map(lastName).toProperty("lastName")
        .map(birthDate).toProperty("birthDate")
        .map(employed).toProperty("employed")
        .map(occupation).toProperty("occupation")
        .build()
        .render(RenderingStrategy.MYBATIS3);
    batchInsert.insertStatements().forEach(mapper::insert);
    session.commit();
} finally {
    session.close();
}

The same idea can be applied directly with JDBC by enabling rewriteBatchedStatements=true and using addBatch():

Connection connection = DriverManager.getConnection(
    "jdbc:mysql://127.0.0.1:3306/mydb?useUnicode=true&characterEncoding=UTF-8&useServerPrepStmts=false&rewriteBatchedStatements=true",
    "root", "root");
connection.setAutoCommit(false);
PreparedStatement ps = connection.prepareStatement("insert into tb_user (name) values(?)");
for (int i = 0; i < stuNum; i++) {
    ps.setString(1, name);
    ps.addBatch();
}
ps.executeBatch();
connection.commit();
connection.close();

Experiments show that using ExecutorType.BATCH reduces the total insertion time to under two seconds, while a foreach‑based approach with thousands of rows can take many minutes.

In summary, for MyBatis batch inserts prefer the ExecutorType.BATCH method; if you must use <foreach>, keep each batch size between 20 and 50 rows.

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.

performancemysqlMyBatisBatch InsertExecutorType.BATCH
Java Captain
Written by

Java Captain

Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.

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.