在 MyBatis 中进行批量数据插入时,XML 的 foreach
和 Java 的循环(结合不同提交策略) 性能差异主要体现在 网络开销、数据库事务、SQL 解析效率 等方面。以下是详细对比:
1. XML 的 foreach
(单条 SQL 批量插入)
INSERT INTO table (col1, col2)
VALUES
<foreach collection="list" item="item" separator=",">
(#{item.val1}, #{item.val2})
</foreach>
特点:
- 单次请求:生成一条
INSERT INTO ... VALUES (..), (..), ...
语句,仅需一次数据库请求。 - 高效的事务:默认在一个事务中执行(需确保事务配置合理)。
- 数据库优化:多数数据库对单条多值插入有优化(如预编译、批量写入磁盘)。
优点:
- 网络延迟低:仅需一次网络往返。
- SQL 解析快:数据库只需解析一次 SQL。
缺点:
- SQL 长度限制:数据量极大会导致 SQL 过长(需分批次)。
- 内存压力:拼接超大 SQL 可能占用较多 JVM 内存。
2. Java 的循环(逐条插入)
for (Item item : list) {
mapper.insert(item);
}
特点:
- 多次请求:每条数据单独执行一次
INSERT
,产生多次网络请求。 - 事务开销大:默认每条插入独立提交(除非手动开启事务)。
缺点:
- 性能极差:网络延迟和事务提交次数是主要瓶颈。
- 不推荐生产使用:仅适用于极小数据量。
3. Java 的循环 + MyBatis Batch 模式
SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH);
try {
Mapper mapper = session.getMapper(Mapper.class);
for (Item item : list) {
mapper.insert(item);
}
session.commit();
} finally {
session.close();
}
特点:
- 批量提交:MyBatis 将多个
INSERT
打包成一个批次发送(具体取决于 JDBC 驱动)。 - 事务统一:所有操作在一个事务中提交。
优点:
- 网络开销低:JDBC 驱动可能将多个操作合并发送(如 MySQL 的
rewriteBatchedStatements
参数)。 - 避免 SQL 长度限制:适合超大数据量(自动分批)。
缺点:
- 略慢于 XML
foreach
:数据库需处理多条 SQL(但比逐条插入快 10 倍以上)。 - 驱动兼容性:并非所有 JDBC 驱动都优化了批量模式(需验证)。
性能对比总结
方案 | 网络请求次数 | SQL 解析次数 | 适合场景 | 性能排序(高 → 低) |
---|---|---|---|---|
XML foreach | 1 | 1 | 中小数据量(单次 SQL 可控) | 1 |
Java Batch 模式 | 1(批次) | N(但优化) | 大数据量(避免 SQL 过长) | 2(接近方案1,依赖驱动优化) |
Java 逐条插入(无事务) | N | N | 不推荐 | 3 |
选型建议
- 中小数据量(1k~10w 条):优先用 XML
foreach
(简单高效)。 - 超大数据量(>10w 条):用 Java Batch 模式 + 分批次提交(避免内存溢出)。
- 动态 SQL 灵活性需求:Batch 模式更灵活(如插入前做业务判断)。
附加优化
- JDBC 参数调优:如 MySQL 的
rewriteBatchedStatements=true
可提升 Batch 模式性能。 - 事务控制:确保批量操作在一个事务中。
- 批次大小:Batch 模式建议每 500~2000 条提交一次(平衡内存和性能)。
通过合理选择方案和调优,可显著提升 MyBatis 批量插入性能。
欢迎关注公众号:“全栈开发指南针”
这里是技术潮流的风向标,也是你代码旅程的导航仪!🚀
Let’s code and have fun! 🎉