// 堆代码 duidaima.com // 错误示例:逐行读取+逐条插入 public void importExcel(File file) { List<Product> list = ExcelUtils.readAll(file); // 一次加载到内存 for (Product product : list) { productMapper.insert(product); // 逐行插入 } }这种写法会引发三大致命问题:
幕后黑手:每次insert都涉及事务提交、索引维护、日志写入
// 正确写法:分段读取(以HSSF为例) OPCPackage pkg = OPCPackage.open(file); XSSFReader reader = new XSSFReader(pkg); SheetIterator sheets = (SheetIterator) reader.getSheetsData(); while (sheets.hasNext()) { try (InputStream stream = sheets.next()) { Sheet sheet = new XSSFSheet(); // 流式解析 RowHandler rowHandler = new RowHandler(); sheet.onRow(row -> rowHandler.process(row)); sheet.process(stream); // 不加载全量数据 } }⚠️ 避坑指南:
// 分页批量插入(每1000条提交一次) public void batchInsert(List<Product> list) { SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH); ProductMapper mapper = sqlSession.getMapper(ProductMapper.class); int pageSize = 1000; for (int i = 0; i < list.size(); i += pageSize) { List<Product> subList = list.subList(i, Math.min(i + pageSize, list.size())); mapper.batchInsert(subList); sqlSession.commit(); sqlSession.clearCache(); // 清理缓存 } }关键参数调优:
# MyBatis配置 mybatis.executor.batch.size=1000 # 连接池(Druid) spring.datasource.druid.maxActive=50 spring.datasource.druid.initialSize=10第三招:异步化处理
阶段 | 操作 | 耗时对比 |
---|---|---|
单线程 | 逐条读取+逐条插入 | 基准值100% |
批处理 | 分页读取+批量插入 | 时间降至5% |
多线程分片 | 按Sheet分片,并行处理 | 时间降至1% |
分布式分片 | 多节点协同处理(如Spring Batch集群) | 时间降至0.5% |
// 错误:边插入边校验,可能污染数据库 public void validateAndInsert(Product product) { if (product.getPrice() < 0) { throw new Exception("价格不能为负"); } productMapper.insert(product); }✅ 正确实践:
// Spring Boot配置Prometheus指标 @Bean public MeterRegistryCustomizer<PrometheusMeterRegistry> metrics() { return registry -> registry.config().meterFilter( new MeterFilter() { @Override public DistributionStatisticConfig configure(Meter.Id id, DistributionStatisticConfig config) { return DistributionStatisticConfig.builder() .percentiles(0.5, 0.95) // 统计中位数和95分位 .build().merge(config); } } ); }四、百万级导入性能实测对比
方案 | 内存峰值 | 耗时 | 吞吐量 |
---|---|---|---|
传统逐条插入 | 2.5GB | 96分钟 | 173条/秒 |
分页读取+批量插入 | 500MB | 7分钟 | 2381条/秒 |
多线程分片+异步批量 | 800MB | 86秒 | 11627条/秒 |
分布式分片(3节点) | 300MB/节点 | 29秒 | 34482条/秒 |