当前位置: 首页 > news >正文

java 如何批量从文件中读取50w数据批量插入数据库,需要用多线程,并且防止jvm内存溢出

在 Java 中从文件中读取大量数据(例如 50 万条记录)并批量插入数据库时,使用多线程和防止 JVM 内存溢出是一个挑战。以下是一个可能的解决方案,涉及分块读取文件、使用多线程进行数据库插入,以及适当的内存管理。

步骤概述

  1. 分块读取文件:将文件内容按块读取到内存中,每块包含一定数量的记录(例如 1000 条记录)。
  2. 使用多线程:创建一个线程池,每个线程负责处理一个数据块并将其插入数据库。
  3. 批量插入:使用 JDBC 批量插入(batch insert)来减少数据库交互次数。
  4. 内存管理:确保每次处理完一个数据块后,及时释放相关内存。

代码示例

以下是一个简化的示例代码,展示如何实现上述步骤:

java复制代码



import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
 
public class BatchInsertExample {
 
    private static final int BATCH_SIZE = 1000; // 每次读取的记录数
    private static final int THREAD_POOL_SIZE = 10; // 线程池大小
    private static final String DB_URL = "jdbc:mysql://localhost:3306/yourdatabase";
    private static final String DB_USER = "yourusername";
    private static final String DB_PASSWORD = "yourpassword";
 
    public static void main(String[] args) {
        String filePath = "path/to/your/largefile.txt";
        ExecutorService executorService = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
 
        try (BufferedReader br = new BufferedReader(new FileReader(filePath))) {
            String line;
            List<String[]> batchData = new ArrayList<>(BATCH_SIZE);
 
            while ((line = br.readLine()) != null) {
                String[] record = parseLine(line); // 解析每行数据
                batchData.add(record);
 
                if (batchData.size() == BATCH_SIZE) {
                    executorService.submit(new InsertTask(batchData));
                    batchData.clear(); // 清除已处理的数据,释放内存
                }
            }
 
            // 提交剩余的数据(如果不足BATCH_SIZE)
            if (!batchData.isEmpty()) {
                executorService.submit(new InsertTask(batchData));
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            executorService.shutdown();
            while (!executorService.isTerminated()) {
                // 等待所有任务完成
            }
        }
    }
 
    private static String[] parseLine(String line) {
        // 根据你的文件格式解析每行数据
        // 示例:假设每行包含三个字段,用逗号分隔
        return line.split(",");
    }
 
    static class InsertTask implements Runnable {
        private final List<String[]> data;
 
        public InsertTask(List<String[]> data) {
            this.data = data;
        }
 
        @Override
        public void run() {
            String insertSQL = "INSERT INTO your_table (field1, field2, field3) VALUES (?, ?, ?)";
 
            try (Connection conn = DriverManager.getConnection(DB_URL, DB_USER, DB_PASSWORD);
                 PreparedStatement pstmt = conn.prepareStatement(insertSQL)) {
 
                conn.setAutoCommit(false); // 关闭自动提交,启用事务
 
                for (String[] record : data) {
                    pstmt.setString(1, record[0]);
                    pstmt.setString(2, record[1]);
                    pstmt.setString(3, record[2]);
                    pstmt.addBatch();
                }
 
                int[] result = pstmt.executeBatch(); // 执行批量插入
                conn.commit(); // 提交事务
 
                // 可选:打印插入结果
                for (int count : result) {
                    System.out.println("Inserted rows: " + count);
                }
 
            } catch (SQLException e) {
                e.printStackTrace();
                // 可以在这里处理回滚等逻辑
            }
        }
    }
}

注意事项

  1. 数据库连接池:对于生产环境,建议使用数据库连接池(如 HikariCP)来管理数据库连接,以提高性能和资源利用率。
  2. 错误处理:示例代码中的错误处理较为简单,应根据实际需求增加重试机制、日志记录等。
  3. 数据解析parseLine 方法应根据你的文件格式进行适当修改。
  4. 内存监控:在处理大规模数据时,可以使用 JVM 监控工具(如 VisualVM)来监控内存使用情况,确保不会发生内存溢出。

通过上述方法,你可以有效地从文件中读取大量数据并批量插入数据库,同时避免 JVM 内存溢出问题。

相关文章:

  • 八、敏捷开发工具:自动化测试工具
  • gitee SSH 公钥设置教程
  • Jenkins 调用 Shell 脚本,在Shell脚本中调用 Unity 类方法,传递参数给Unity
  • SQLMesh 系列教程5- 详解SQL模型
  • spring security认证和授权流程
  • 对比机器学习揭示了跨物种共享与特异性的脑功能结构|文献速递-医学影像人工智能进展
  • 自动化测试平台ATECLOUD全面解析
  • “文化平权”不再遥远?昆仑万维开源首个面向 AI 短剧创作视频生成模型SkyReels-V1
  • vlanif接口转发vlan
  • 直流稳压电源工作原理_带反馈
  • JAVA过滤器(学习自用)
  • [算法学习笔记]1. 枚举与暴力
  • DeepSeek V3和R1
  • ComfyUI创建自定义节点
  • 分析算法时间复杂度基本方法和步骤
  • 网络安全的态势如何以及如何解决?
  • 【Spring详解一】Spring整体架构和环境搭建
  • 防御保护选路练习
  • 如何优化Spark作业的性能
  • 1-知识图谱-概述和介绍
  • 夜读丨最美的风景,在亲人的目光里
  • 上海市委常委会扩大会议传达学习习近平总书记考察上海重要讲话和在部分省区市“十五五”时期经济社会发展座谈会上的重要讲话精神
  • 白俄罗斯政府代表团将访问朝鲜
  • 两个灵魂,一支画笔,意大利艺术伴侣的上海灵感之旅
  • 电商平台集体出手,多措并举助力外贸企业拓内销
  • 青海大学常务副校长(正厅级)任延明已任省卫健委党组书记