最有效的做法是将数据库或文件读写操作从循环中抽出,采用批量处理而非反复建立连接、执行语句和关闭资源:如用IN批量查询替代循环单查,addBatch/executeBatch替代循环executeUpdate,统一管理IO资源,提前加载数据至内存计算。

直接把数据库或文件读写操作从循环里抽出来,是避免性能瓶颈最有效的做法。核心原则是:一次批量处理,而不是反复建立连接、执行语句、再关闭。
批量查询替代逐条查库
比如要根据一批用户 ID 查询用户信息,不要写 for 循环里每次查一个:
- ❌ 错误示范:
for (Long id : userIdList) { userMapper.selectById(id); } - ✅ 正确做法:用
IN语句一次性查出全部,如userMapper.selectBatchIds(userIdList);若 ID 数量超限(如 MySQL 默认 1000),可分批,每批 500 或 1000 条,仍远优于单条循环 - 注意:确保数据库表对查询字段建了索引,否则
IN批量也可能变慢
用 PreparedStatement 批处理写库
插入、更新、删除大量数据时,别在循环里反复 executeUpdate():
- ❌ 错误示范:
for (User u : userList) { stmt.executeUpdate("INSERT ... VALUES (" + u.getName() + ")"); } - ✅ 正确做法:使用
addBatch()+executeBatch(),提前预编译 SQL,一次提交多条 - 建议配合
setFetchSize()和事务控制(如每 1000 条 commit 一次),防止内存溢出或锁表过久
IO 资源统一管理,不在循环内开闭
读文件、调用远程接口、访问缓存等 IO 操作,同样忌讳“开–用–关”套在循环里:
立即学习“Java免费学习笔记(深入)”;
- ❌ 错误示范:
for (String path : paths) { FileInputStream fis = new FileInputStream(path); ... fis.close(); } - ✅ 正确做法:循环外打开资源(如用
BufferedReader读一个大文件),循环内只做解析;或用try-with-resources管理单次 IO,但绝不嵌套在循环中重复创建 - 网络请求类场景,优先用连接池(如 Apache HttpClient 的
PoolingHttpClientConnectionManager),复用底层 TCP 连接
提前加载 + 内存计算代替实时 IO
如果业务允许,把需要多次访问的数据一次性加载到内存,后续逻辑走本地计算:
- 例如导出报表前,先查出所有相关订单、商品、用户数据,组装成 DTO 列表;导出循环只遍历内存对象,不触发任何 DB 或 Redis 调用
- 注意权衡:数据量太大时需分页加载或流式处理,避免 OOM;变化频繁的数据要评估缓存一致性
- 可结合 Guava Cache 或 Caffeine 做轻量级本地缓存,设置合理过期时间


















