You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

JDBC向MS SQL批量插入10万条数据遇1000元素限制问题

我来分享下我用JDBC向MS SQL批量插入10万条姓名数据的实现方案——因为MS SQL限制单条INSERT语句最多包含1000个元素,所以我特意把数据集拆成了每组不超过1000条的子集来处理,同时用线程池优化插入效率:

实现思路
  • 分批次处理: 每次从待插入列表中提取最多1000条数据,规避MS SQL的单条INSERT元素上限
  • SQL语句拼接: 用StringJoiner简化批量INSERT语句的构建,不用手动拼接繁琐的字符串
  • 并行插入: 借助固定大小的线程池,让多个批次的插入任务并行执行,提升整体插入速度
代码实现
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.StringJoiner;
import java.sql.Connection;
import java.sql.Statement;

public class BatchNameInserter {
    public void batchInsertNames(List<String> names) {
        // 初始化SQL拼接器,预设INSERT语句的前后部分,中间用'), ('分隔每个姓名
        StringJoiner sqlJoiner = new StringJoiner("'), ('", "INSERT INTO Names (Name) VALUES ('", "');");
        // 创建固定100线程的线程池,可根据数据库承载能力调整大小
        ExecutorService threadPool = Executors.newFixedThreadPool(100);

        while (!names.isEmpty()) {
            // 每次取最多1000条数据,避免触发MS SQL的限制
            int batchSize = Math.min(1000, names.size());
            // 提取当前批次的姓名,用HashSet做批次内去重(如果原始数据无重复可省略)
            HashSet<String> currentBatch = new HashSet<>(names.subList(0, batchSize));
            // 移除已处理的批次数据,避免重复插入
            names.subList(0, batchSize).clear();

            // 提交当前批次的插入任务到线程池
            threadPool.submit(() -> {
                // 用try-with-resources自动管理JDBC资源,避免泄漏
                try (Connection conn = /* 这里替换成你的JDBC连接获取逻辑 */;
                     Statement stmt = conn.createStatement()) {
                    sqlJoiner.reset();
                    currentBatch.forEach(sqlJoiner::add);
                    String insertSql = sqlJoiner.toString();
                    // 执行批量插入
                    stmt.executeUpdate(insertSql);
                } catch (Exception e) {
                    // 生产环境建议替换为日志记录+重试逻辑
                    System.err.println("批次插入失败: " + e.getMessage());
                    e.printStackTrace();
                }
            });
        }

        // 关闭线程池并等待所有任务完成
        threadPool.shutdown();
        try {
            // 设置超时时间,防止无限等待
            if (!threadPool.awaitTermination(1, java.util.concurrent.TimeUnit.HOURS)) {
                threadPool.shutdownNow();
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            threadPool.shutdownNow();
            e.printStackTrace();
        }
    }
}
注意事项
  • 资源管理: 务必用try-with-resources管理JDBC连接、Statement等资源,确保资源能被自动释放
  • 线程池调优: 100线程的设置不是固定值,需要根据你的数据库连接池最大连接数调整,避免线程过多导致连接耗尽
  • 异常处理: 代码里的异常处理只是基础示例,生产环境建议加入失败重试、错误数据记录等逻辑,方便后续排查和补插
  • 去重逻辑: 如果原始姓名数据已经保证唯一,可以去掉HashSet的转换,减少不必要的性能开销

内容的提问来源于stack exchange,提问作者Ploni Almoni

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:28:53