无法将百万条CSV记录插入MySQL数据库,寻求批量处理及每百行打印的代码实现方案
解决百万条CSV插入MySQL失败+每100行打印的问题
我来帮你搞定这两个问题,咱们先拆解需求再调整代码:
一、实现每读取100行就打印的功能
这个很简单,你只需要在读取CSV记录的循环里加一个计数器,每次循环后判断计数器是否是100的倍数就行。具体位置就在遍历CSVRecord的那个for循环里,看下面的代码示例就能明白。
二、解决百万条数据插入失败的问题
你现在的代码是把所有百万条数据先塞进ArrayList,再一次性批量插入,这会导致两个核心问题:
- 内存溢出:百万条对象存在List里,内存占用会非常大,直接撑爆JVM
- MySQL批量插入限制:MySQL的
max_allowed_packet和JDBC批处理的缓冲区都有上限,一次性提交太多数据会被数据库拒绝
解决办法是分批提交:比如每读取1000条就执行一次批处理并提交,同时清空批处理缓冲区,避免内存占用过高。另外还要用try-with-resources自动管理资源(比如BufferedReader、Connection、PreparedStatement),避免资源泄漏。
优化后的完整代码
import org.apache.commons.csv.CSVFormat; import org.apache.commons.csv.CSVParser; import org.apache.commons.csv.CSVRecord; import java.io.BufferedReader; import java.io.FileReader; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; public class CsvToMysql { private static final int BATCH_SIZE = 1000; // 每1000条提交一次,可根据机器性能调整 private static final int PRINT_INTERVAL = 100; // 每100行打印一次进度 public static void main(String[] args) { String csvFilePath = "C:\\Student1.csv"; // 使用try-with-resources自动关闭资源,避免手动关闭遗漏导致泄漏 try (BufferedReader lineReader = new BufferedReader(new FileReader(csvFilePath)); CSVParser records = CSVParser.parse(lineReader, CSVFormat.EXCEL.withFirstRecordAsHeader().withIgnoreHeaderCase().withTrim()); Connection con = dbconnection(); PreparedStatement statement = con.prepareStatement("INSERT INTO test12(DOB, NAME, GENDER) VALUES (?, ?, ?)")) { int rowCount = 0; for (CSVRecord record : records) { rowCount++; // 每读取100行打印一次进度 if (rowCount % PRINT_INTERVAL == 0) { System.out.println("已读取并处理 " + rowCount + " 行数据"); } // 给预编译语句设置参数 statement.setString(1, record.get(0)); statement.setString(2, record.get(1)); statement.setString(3, record.get(2)); statement.addBatch(); // 每积累到BATCH_SIZE条,执行批处理并提交事务 if (rowCount % BATCH_SIZE == 0) { statement.executeBatch(); con.commit(); statement.clearBatch(); // 清空批处理缓冲区,避免内存堆积 System.out.println("已成功插入 " + rowCount + " 条数据"); } } // 处理最后一批不足BATCH_SIZE的数据 if (rowCount % BATCH_SIZE != 0) { statement.executeBatch(); con.commit(); System.out.println("已成功插入最后一批数据,总计 " + rowCount + " 条"); } } catch (SQLException ex) { ex.printStackTrace(); // 出现异常时回滚事务,避免部分插入导致数据不一致 try (Connection con = dbconnection()) { if (con != null) { con.rollback(); } } catch (SQLException e) { e.printStackTrace(); } } catch (Exception ex) { ex.printStackTrace(); } } public static Connection dbconnection() { Connection connection = null; try { Class.forName("com.mysql.cj.jdbc.Driver"); connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/newschema1", "root", "12345"); connection.setAutoCommit(false); // 关闭自动提交,手动控制事务 System.out.println("数据库连接成功"); } catch (ClassNotFoundException | SQLException e) { e.printStackTrace(); } return connection; } }
关键优化点说明
- 每100行打印:在遍历CSV记录的循环中加入
rowCount计数器,当rowCount % PRINT_INTERVAL == 0时打印当前处理进度 - 分批提交:设置
BATCH_SIZE(可根据机器性能调整),每积累到这个数量就执行executeBatch()并commit(),同时清空批处理缓冲区 - 资源自动管理:用
try-with-resources包裹所有需要关闭的资源,不用手动调用close(),避免资源泄漏 - 异常回滚:当SQL异常发生时,回滚事务,避免部分插入导致数据不一致
内容的提问来源于stack exchange,提问作者user10025328
相关产品推荐
相关产品推荐

