Mastering Batch Updates in MyBatis: From foreach to ON DUPLICATE KEY
This article explores four common batch‑update techniques in MyBatis, compares their performance, shows how to configure Druid and Spring Boot to allow multi‑statement execution, and provides practical code examples and configuration tips for reliable large‑scale data updates.
Introduction
A colleague asked how to write batch‑update code in a real project. The article shares several practical solutions and configuration tricks to make batch updates efficient and reliable.
1. Using foreach for batch update
The following MyBatis XML uses
<foreach>to generate a single UPDATE statement for each entity in a list, avoiding multiple round‑trips to the database:
<code><update id="updateForBatch" parameterType="cn.net.susan.entity.sys.UserEntity">
<foreach collection="list" item="entity" separator=";">
UPDATE sys_user
SET password = #{entity.password},
update_user_id = #{entity.updateUserId},
update_user_name = #{entity.updateUserName}
<where>
id = #{entity.id}
</where>
</foreach>
</update>
</code>Compared with a simple
forloop that issues an UPDATE per iteration, the foreach approach reduces network overhead by sending a single batch request.
2. Other batch‑update approaches
Case‑when method – builds a massive UPDATE with conditional assignments:
<code><update id="updateForBatch" parameterType="cn.net.susan.entity.sys.UserEntity">
UPDATE sys_user
<trim prefix="set" suffixOverrides=",">
<trim prefix="password = case id" suffix=",">
<foreach collection="list" item="item">
WHEN #{item.id} THEN #{item.password}
</foreach>
</trim>
... (similar blocks for other columns) ...
</trim>
<where> id IN ( <foreach collection="list" item="item" separator=",">#{item.id}</foreach> ) </where>
</update>
</code>While flexible, this method generates a very long SQL statement and may have poorer performance.
INSERT … ON DUPLICATE KEY UPDATE – inserts rows and updates existing ones in a single statement:
<code><update id="updateForBatch" parameterType="cn.net.susan.entity.sys.UserEntity">
INSERT INTO sys_user (id, username, password) VALUES
<foreach collection="list" item="item" separator=",">
(#{item.id}, #{item.username}, #{item.password})
</foreach>
ON DUPLICATE KEY UPDATE password = VALUES(password)
</update>
</code>This requires a unique index on the key column (e.g.,
username) and works well when the data volume is moderate.
3. Druid WallFilter blocking multi‑statement batch updates
When using the foreach approach, Druid’s
WallFiltermay raise the error
sql injection violation, multi‑statement not allow. The filter disallows multiple statements in a single SQL string by default.
To enable batch updates, add
&allowMultiQueries=trueto the JDBC URL:
<code>jdbc:mysql://localhost:3306/console?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowMultiQueries=true</code>And adjust Druid’s filter configuration:
<code>spring:
datasource:
druid:
filter:
wall:
config:
multi-statement-allow: true
none-base-statement-allow: true
</code>4. Interaction with ShardingSphere and dynamic datasource
In projects that use ShardingSphere and Baomidou’s dynamic datasource, the Druid configuration must be placed under the same level as the datasource definition. Example YAML snippet:
<code>spring:
datasource:
dynamic:
primary: master
datasource:
master:
url: jdbc:mysql://localhost:3306/susan_mall?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: 123456
druid:
wall:
multiStatementAllow: true
noneBaseStatementAllow: true
</code>After this change, the foreach batch‑update works correctly.
5. Conclusion
The article outlines four batch‑update strategies:
Individual updates inside a for‑loop.
Foreach‑generated batch UPDATE (recommended).
Case‑when conditional UPDATE.
INSERT … ON DUPLICATE KEY UPDATE.
The foreach method provides the best balance of simplicity and performance, but the batch size should be kept under 1,000 rows to avoid excessive load. When encountering the Druid multi‑statement error, enable
allowMultiQueriesin the JDBC URL and set the appropriate WallFilter flags.
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.
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.