Improving MyBatis Batch Insert Performance with ExecutorType.BATCH and foreach Optimization

The article explains why MyBatis batch inserts using a foreach-generated single INSERT statement can cause severe CPU and latency issues, and demonstrates how to achieve fast bulk insertion by limiting batch size or switching to ExecutorType.BATCH with code examples.

Java Architect Essentials
Java Architect Essentials
Java Architect Essentials
Improving MyBatis Batch Insert Performance with ExecutorType.BATCH and foreach Optimization

Recently a job in a project suffered high CPU usage due to a MyBatis batch insert that built a huge single INSERT statement using <foreach> in the mapper XML.

The original approach generated many individual INSERT statements or a single statement with thousands of VALUES, which caused long parsing and placeholder‑mapping time, especially when inserting 5000+ rows.

Best practice is to limit the number of VALUES per statement to 20‑50 rows, or better, use MyBatis ExecutorType.BATCH so that each row is inserted with a prepared statement executed in batch mode.

Example of a foreach mapper:

<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>

Using a single multi‑row INSERT reduces round‑trips but still creates a massive statement; MySQL documentation recommends combining rows only up to a reasonable size.

With MyBatis batch executor:

SqlSession session = sessionFactory.openSession(ExecutorType.BATCH);
for (Model model : list) {
    session.insert("insertStatement", model);
}
session.flushStatements();

Alternatively, MyBatis Dynamic SQL can generate a series of small insert statements and execute them via a mapper.

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")
        // ... other columns
        .build()
        .render(RenderingStrategy.MYBATIS3);
    batchInsert.insertStatements().forEach(mapper::insert);
    session.commit();
} finally {
    session.close();
}

Plain JDBC batch example:

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 insertion time to under 2 seconds for thousands of rows, while the foreach approach should keep each batch to about 20‑50 rows for acceptable performance.

In summary, prefer MyBatis batch executor for bulk inserts; if <foreach> must be used, limit the batch size to 20‑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.

SQLMyBatisBatch InsertExecutorType.BATCH
Java Architect Essentials
Written by

Java Architect Essentials

Committed to sharing quality articles and tutorials to help Java programmers progress from junior to mid-level to senior architect. We curate high-quality learning resources, interview questions, videos, and projects from across the internet to help you systematically improve your Java architecture skills. Follow and reply '1024' to get Java programming resources. Learn together, grow together.

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.