批量插入大量数据(例如几十万条)时,如果每条单独插入,会非常慢,内存占用也高。这里总结一种 CSV → Java 对象 → MyBatis 批量插入 的通用实现方法。
1️⃣ 流程概览
-
准备 CSV 文件
-
CSV 文件每行表示一条数据
-
每列对应对象的一个字段
-
-
Java 读取 CSV
-
使用流式读取方式,逐行解析 CSV
-
每行生成一个 Java 对象
-
-
收集对象到列表
-
定义一个
batchList,每次把解析的对象加入列表 -
当列表长度达到批量大小(如 1000 条)时执行批量插入
-
-
批量插入到数据库
-
使用 MyBatis
<foreach>或 JDBC 批处理 -
批量插入完成后,清空列表,继续下一批
-
-
处理剩余数据
- CSV 读完后,如果
batchList还有未满的对象,也要插入一次
- CSV 读完后,如果
2️⃣ Java 读取 CSV 示例
使用 OpenCSV 流式读取:
java
int batchSize = 1000;
List<MyData> batchList = new ArrayList<>();
try (CSVReader reader = new CSVReader(new FileReader("data.csv"))) {
String[] row;
while ((row = reader.readNext()) != null) {
MyData record = new MyData();
record.setField1(row[0].trim());
record.setField2(row[1].trim());
// ...设置其他字段...
batchList.add(record);
if (batchList.size() == batchSize) {
myMapper.insertBatch(batchList); // MyBatis批量插入
batchList.clear(); // 清空列表
}
}
if (!batchList.isEmpty()) {
myMapper.insertBatch(batchList);
}
} catch (IOException e) {
e.printStackTrace();
}
✅ 特点:
-
流式处理:不会一次性占用大量内存
-
分批控制:每批插入数据库,提升性能
3️⃣ MyBatis 批量插入 SQL 示例
XML
<insert id="insertBatch" parameterType="java.util.List">
INSERT INTO my_table (field1, field2, field3)
VALUES
<foreach collection="list" item="item" separator=",">
(#{item.field1}, #{item.field2}, #{item.field3})
</foreach>
</insert>
解释:
-
parameterType="java.util.List":告诉 MyBatis 参数是一个列表 -
<foreach>遍历列表,每个元素用item访问 -
separator=",":每条记录之间用逗号分隔,生成完整 SQL
注意 :SQL 太长可能会超出数据库限制,所以建议 每批 500~1000 条
4️⃣ 原理解析
-
MyBatis 将
List中每个对象的字段替换到#{item.xxx}占位符 -
<foreach>拼接成一条完整的INSERT ... VALUES (...),(...),(...)SQL -
数据库一次执行这条 SQL,即可插入多条记录
-
相比逐条插入,性能提升显著,因为减少了网络往返和事务提交次数
5️⃣ 优化建议
-
批次大小:500~1000 条比较稳,太大可能导致 SQL 超长
-
内存管理:使用流式读取 CSV,不要一次性把所有数据读入内存
-
事务控制:每批单独提交,方便回滚
-
大数据量:超过几十万条,建议使用 JDBC 批处理(ExecutorType.BATCH)
6️⃣ 总结
MyBatis 批量插入的核心就是 把 CSV 转成 Java 对象 → 收集成批 →
<foreach>拼 SQL → 一次性插入数据库好处:
显著减少数据库交互次数
控制内存占用
易于维护和调试