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

批量导入 10 万条数据入库如何实现?—— 从“卡死”到“秒级完成”(Spring Boot + MySQL 实战)

视频看了几百小时还迷糊?关注我,几分钟让你秒懂!(发点评论可以给博主加热度哦)


一、真实痛点:为什么你导入 10 万条数据会卡死?

  • 循环 10 万次,每次INSERT INTO ...
  • 导致数据库连接超时、CPU 100%、内存溢出?
  • 导入花了 2 小时,老板急得跳脚?

🚨根本原因:你用了最原始的单条插入方式,而没用批量处理 + 事务优化 + 连接池调优

本文将手把手教你用Spring Boot + JDBC + MySQL实现10 万条数据 5 秒内入库,附完整代码、反例对比、性能压测!


二、反例警告:这些写法千万别用!

❌ 反例 1:循环单条插入(性能灾难!)

// 每次都开事务、建连接、网络往返 → 10 万次 = 灾难! for (User user : users) { jdbcTemplate.update("INSERT INTO users(name, email) VALUES (?, ?)", user.getName(), user.getEmail()); }

💥实测结果(10 万条)

  • 耗时:1200+ 秒(20 分钟)
  • 数据库 CPU:90%+
  • 网络 I/O:爆炸

❌ 反例 2:全量加载到内存(OOM 风险!)

// 一次性读 10 万条 Excel 到 List<User> → 内存直接爆! List<User> users = excelService.readAll("huge_file.xlsx"); userDao.batchInsert(users);

⚠️ 如果文件是 100 万行?服务器直接OutOfMemoryError


三、正确姿势:分页流式读取 + 批量插入 + 事务控制

✅ 核心思想:

  1. 分块读取:每次读 1000 行,避免 OOM;
  2. 批量插入:每 1000 条执行一次batchUpdate
  3. 手动事务:每批一个事务,失败可回滚,成功快提交;
  4. 关闭自动提交:减少事务开销。

四、手把手实战:Spring Boot 实现高效批量导入

第一步:配置 MySQL(关键!)

# application.yml spring: datasource: url: jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC &rewriteBatchedStatements=true # ←←← 开启批量重写(性能提升 10 倍!) &useServerPrepStmts=false # 批量插入时关闭服务端预编译 username: root password: 123456 hikari: data-source-properties: cachePrepStmts: true prepStmtCacheSize: 250 prepStmtCacheSqlLimit: 2048

🔑rewriteBatchedStatements=true是 MySQL 批量插入提速的关键!


第二步:DAO 层 —— 批量插入方法

@Repository public class UserDao { @Autowired private JdbcTemplate jdbcTemplate; // 每次插入一批(如 1000 条) public void batchInsert(List<User> users) { String sql = "INSERT INTO users(name, email, phone) VALUES (?, ?, ?)"; jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() { @Override public void setValues(PreparedStatement ps, int i) throws SQLException { User user = users.get(i); ps.setString(1, user.getName()); ps.setString(2, user.getEmail()); ps.setString(3, user.getPhone()); } @Override public int getBatchSize() { return users.size(); } }); } }

第三步:Service 层 —— 分块处理 + 事务控制

@Service @Slf4j public class DataImportService { @Autowired private UserDao userDao; // 每批处理 1000 条 private static final int BATCH_SIZE = 1000; @Transactional // ←←← 整个方法一个大事务(可选,见下文说明) public void importUsersFromExcel(String filePath) throws Exception { // 使用流式读取,避免内存溢出 try (InputStream is = new FileInputStream(filePath)) { ExcelReader reader = EasyExcel.read(is, User.class, new AnalysisEventListener<User>() { private List<User> batch = new ArrayList<>(); @Override public void invoke(User user, AnalysisContext context) { batch.add(user); // 达到批次大小,执行批量插入 if (batch.size() >= BATCH_SIZE) { userDao.batchInsert(batch); log.info("已导入 {} 条", context.readRowHolder().getRowIndex()); batch.clear(); } } @Override public void doAfterAllAnalysed(AnalysisContext context) { // 处理最后一批不足 1000 的数据 if (!batch.isEmpty()) { userDao.batchInsert(batch); batch.clear(); } } }).build(); reader.readAll(); } } }

✅ 使用 EasyExcel 实现SAX 模式流式读取,100 万行也不怕 OOM!


五、事务策略选择:大事务 vs 小事务

策略优点缺点适用场景
整个导入一个事务@Transactional数据强一致,失败全回滚事务太大,可能超时、锁表数据量小(<1万),要求原子性
每批一个事务(手动控制)快速提交,失败只影响当前批部分成功部分失败推荐!10万+ 数据首选

✅ 推荐:每批一个事务(去掉@Transactional,改用手动)

// 在 Service 中注入 PlatformTransactionManager @Autowired private PlatformTransactionManager transactionManager; public void importUsersFromExcel(String filePath) throws Exception { // ... @Override public void invoke(User user, AnalysisContext context) { batch.add(user); if (batch.size() >= BATCH_SIZE) { // 手动开启事务 TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition()); try { userDao.batchInsert(batch); transactionManager.commit(status); // 提交 } catch (Exception e) { transactionManager.rollback(status); // 回滚当前批 log.error("批次导入失败,已回滚", e); throw e; } batch.clear(); } } }

六、性能对比(实测 10 万条数据)

方案耗时CPU内存可靠性
单条插入1200+ 秒90%+低(易超时)
批量插入(无分块)45 秒60%极高(OOM 风险)
分块 + 批量 + 流式读取5.2 秒40%

📌提速 200 倍以上!


七、高级优化技巧

1️⃣ 临时关闭索引(仅限 MyISAM 或 InnoDB 大量导入)

-- 导入前 ALTER TABLE users DISABLE KEYS; -- 执行批量导入 -- 导入后 ALTER TABLE users ENABLE KEYS;

⚠️ InnoDB 不支持DISABLE KEYS,但可考虑先删索引,后重建(谨慎使用)。


2️⃣ 调整 MySQL 参数(需 DBA 权限)

# my.cnf innodb_buffer_pool_size = 2G # 增大缓冲池 innodb_log_file_size = 512M # 增大日志文件 bulk_insert_buffer_size = 256M # MyISAM 专用

3️⃣ 使用LOAD DATA INFILE(终极方案)

// 直接生成 CSV,调用 MySQL 命令 String sql = "LOAD DATA LOCAL INFILE '/tmp/users.csv' INTO TABLE users FIELDS TERMINATED BY ','"; jdbcTemplate.execute(sql);

速度最快(10 万条 < 1 秒),但需文件在 DB 服务器或开启local_infile


八、避坑指南

⚠️ 坑 1:忘记rewriteBatchedStatements=true

MySQL 默认不重写批量语句,batchUpdate退化为单条执行!

⚠️ 坑 2:批量太大导致max_allowed_packet超限

调整 MySQL 配置:max_allowed_packet = 64M

⚠️ 坑 3:Excel 读取用XSSFWorkbook(POI)

它会把整个文件加载到内存!必须用 EasyExcel 或 SXSSF


九、完整依赖(Maven)

<!-- EasyExcel(阿里开源,流式读取) --> <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>3.3.2</version> </dependency> <!-- Spring Boot JDBC --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency>

十、总结:批量导入黄金法则

  1. 不要单条插入→ 用batchUpdate
  2. 不要全量加载→ 用流式读取(EasyExcel);
  3. 不要默认配置→ 开启rewriteBatchedStatements=true
  4. 不要大事务→ 每批一个事务;
  5. 监控进度→ 加日志,让用户知道“没卡死”。

记住
10 万条不是问题,100 万条也能秒级搞定——关键在“批量 + 流式 + 调优”!


视频看了几百小时还迷糊?关注我,几分钟让你秒懂!(发点评论可以给博主加热度哦)

http://www.jsqmd.com/news/322060/

相关文章:

  • 沃尔玛购物卡回收6种通用方法
  • 第三方软件测评机构【Apifox Mock数据拼接技巧:如何生成符合业务规则的复合数据】
  • 2026年靠谱的全屋定制服务推荐,看看费用和性价比哪家强
  • 【毕业设计】基于SpringBoot的海洋航运管理系统的设计与实现(源码+文档+远程调试,全bao定制等)
  • 2026年 玻璃纤维布厂家推荐排行榜,电子级/脱模压板/风电叶片/预浸料/柔性光伏/陶瓷化硅橡胶/云母带/超薄/无碱玻璃纤维布,创新材料与卓越性能深度解析
  • 2026年北京口碑好的全屋定制品牌推荐,OLO我乐定制通州居然店可信度高吗
  • 手把手教会你写单元测试 —— 从“不敢测”到“测得爽”(Spring Boot + JUnit 5 实战)
  • 2026松原工控产品:口碑厂家,助力高效生产,工控产品/施耐德电气/电气自动化/中低压电气,工控产品品牌有哪些
  • 西门子200smart系列化工反应釜程序探索
  • 国科大《ACS Omega》突破:1秒颠覆传统烧结!焦耳热冲击创制“双峰”晶粒SiC,晶粒尺寸激增60%
  • 第二届天文学与光学测量国际学术会议(AOM 2026
  • Java 数据结构你会用几种?—— 从“只会 ArrayList”到“精准选型”(附 Spring Boot 实战场景)
  • 【计算机毕业设计案例】基于springboot+vue的奶茶店线下点餐管理系统基于SpringBoot的奶茶店线上点单与库存管理系统设计与实现(程序+文档+讲解+定制)
  • 线下文档到 AI 知识库(AI-KB):企业内容数字化的新路径
  • 200smart 与威纶通触摸屏实现平面两轴直线插补(Ver1.2.7)
  • 《Nat. Commun.》:南昌大学/宁夏大学团队揭示脉冲加热动力学稳定机制,实现负载金属纳米颗粒的抗烧结锁定
  • 手把手教会你什么是 Spring 事件监听 —— 解耦神器,告别“面条代码”!(Spring Boot 实战)
  • 用户个人资料编辑功能:测试要点、陷阱与最佳实践
  • 机床排屑机厂家报价口碑推荐,选购、运维与售后关键要点分析
  • 2026年1月云真机、云手机、安卓云手机、苹果云手机、ios云手机厂家实力综合分析:天勤网络登顶
  • 订单提交手动测试流程指南
  • Claude Code提示词案例(开发联系我们页面,表单使用Element Plus的el-form组件实现)
  • 2026年 展位设计公司推荐排行榜:主题展位/品牌展位/特装展位/大小面积展位设计搭建,创意视觉与高效落地的专业服务商精选
  • 国内四大AI编程IDE对比(二):从零构建桌面应用实测(补上Trae,幸亏补上了)
  • ACPI!ACPIBuildProcessDeviceGenericEvalStrict函数和BuildRequest->CurrentObject的由来
  • 一个杀手级 prompt
  • Google Genie 3 技术架构拆解:世界模型如何为 Agent 训练提供无限环境
  • threoninamide;DFCYDWOTPTH-NH₂
  • 雨生红球藻主流品牌全景解析(2026年最新版)
  • 基于springboot的电影评价管理系统设计实现