核心是分批读取+批量写入+事务控制+流式处理:禁用全量加载,CSV用OpenCSV迭代、Excel用POI SXSSF、日志用BufferedReader;JDBC启用addBatch/executeBatch并合理设批次大小;按批次提交事务,辅以校验、错误隔离与进度监控。

Java 中大文件批量导入数据库,核心是避免内存溢出、提升导入效率、保证数据一致性。关键不在“一次读完再插入”,而在于“分批读取 + 批量写入 + 事务控制 + 流式处理”。
分块读取文件,避免 OOM
不要用 FileReader 或 Files.readAllLines() 一次性加载整个文件——几 GB 的 CSV 或 Excel 会直接触发 OutOfMemoryError。应使用流式逐行/逐片读取:
- CSV:用
OpenCSV(CsvToBeanBuilder配合LineProcessor)或Apache Commons CSV的Iterable<csvrecord></csvrecord>进行迭代解析 - Excel(.xlsx):用
Apache POI SXSSFWorkbook(而非XSSFWorkbook),它基于磁盘临时文件缓存,支持流式读取行,内存占用可控 - 文本日志类文件:用
BufferedReader+readLine(),配合计数器每 N 行为一个批次
分批插入 + JDBC 批量操作
单条 INSERT 执行几百上千万次,性能极差。必须启用 JDBC 批量模式:
- 设置
PreparedStatement.addBatch()+executeBatch(),每 1000~5000 条执行一次(根据字段复杂度和数据库负载调整) - 连接 URL 加参数提升批量效率,例如 MySQL:
?rewriteBatchedStatements=true(将多条 INSERT 合并为INSERT ... VALUES (),(),...) - PostgreSQL 可用
copy协议(通过CopyManager),比 JDBC 插入快 5~10 倍,但需文件可被数据库服务器访问
事务粒度要合理
整个文件包在一个事务里?风险高(失败则全部回滚,耗时长、锁表久);每行一个事务?性能差、日志暴涨。推荐按批次提交:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
立即学习“Java免费学习笔记(深入)”;
- 每个批量插入(如 2000 条)作为一个逻辑单元,在成功执行
executeBatch()后调用connection.commit() - 捕获异常时,记录当前批次起始行号、错误原因,跳过该批次或尝试修复后重试(需幂等设计)
- 开启手动事务:
connection.setAutoCommit(false),并在 finally 块中确保 commit/rollback
补充健壮性措施
生产环境不能只管“插进去”,还要防错、可观测、可恢复:
- 字段校验前置:在解析阶段做基础非空、格式校验(如日期、数字),失败行写入 error.log 并继续,不阻塞整体流程
- 主键/唯一冲突处理:用
INSERT IGNORE(MySQL)或ON CONFLICT DO NOTHING(PostgreSQL),或先查后插(慎用,影响性能) - 进度与日志:用
AtomicLong记录已处理行数,结合 SLF4J 打印每万行耗时、当前批次状态 - 断点续传(可选):将已成功导入的最大行号/标识存入数据库或临时文件,程序重启后从该位置继续
不复杂但容易忽略——真正卡住的往往不是代码逻辑,而是数据库连接池配置(如最大活跃连接数)、JVM 堆外内存(POI SXSSF 的临时文件)、以及目标表是否建了合适索引(大批量导入前可考虑暂时禁用非必要索引,导入完成后再重建)。

















