如何同时调用多个方法?同一方法内多查询并行实现问询
关于多DAO方法调用与结果存储的技术建议
当然可以同时调用这些方法啦!你当前的写法是同步串行执行,完全能满足需求——每个DAO方法执行完毕后,把结果存入对应的List,后续在当前方法里直接使用这些集合就好。不过我们可以根据实际场景优化得更高效、更健壮:
一、基础串行写法的注意事项
你的现有代码逻辑清晰,适合数据量小、对性能要求不高的场景:
List<Student> students = studentMao.getAll(collegeId); List<Department> departments = departmentsMao.getByCollegeId(collegeId); List<College> colleges = collegeMao.getByUniversityId(universityId);
但要注意:如果其中某个DAO方法抛出异常,后续的方法调用会被中断。如果希望每个调用独立执行(比如即使查学生失败,也要继续查院系),可以给每个调用加上异常捕获:
List<Student> students = Collections.emptyList(); try { students = studentMao.getAll(collegeId); } catch (Exception e) { // 这里可以记录日志,或者返回空集合兜底 log.error("获取学生列表失败", e); } List<Department> departments = Collections.emptyList(); try { departments = departmentsMao.getByCollegeId(collegeId); } catch (Exception e) { log.error("获取院系列表失败", e); } // 同理处理colleges
二、并行调用提升执行效率
如果这三个DAO方法是完全独立的(比如分别查询不同的数据库表,互相没有依赖关系),那可以用CompletableFuture实现并行调用,减少总耗时(总耗时约等于耗时最长的那个方法的执行时间,而非三个方法时间相加):
// 异步提交三个查询任务 CompletableFuture<List<Student>> studentFuture = CompletableFuture.supplyAsync(() -> studentMao.getAll(collegeId)); CompletableFuture<List<Department>> deptFuture = CompletableFuture.supplyAsync(() -> departmentsMao.getByCollegeId(collegeId)); CompletableFuture<List<College>> collegeFuture = CompletableFuture.supplyAsync(() -> collegeMao.getByUniversityId(universityId)); // 等待所有任务完成 CompletableFuture.allOf(studentFuture, deptFuture, collegeFuture).join(); // 取出各任务结果 List<Student> students = studentFuture.join(); List<Department> departments = deptFuture.join(); List<College> colleges = collegeFuture.join();
并行调用的关键注意点:
- 线程池配置:默认
CompletableFuture使用JDK的ForkJoinPool,如果你的应用有自定义线程池,建议传入自定义池,避免默认线程资源被耗尽:ExecutorService customPool = Executors.newFixedThreadPool(3); CompletableFuture<List<Student>> studentFuture = CompletableFuture.supplyAsync(() -> studentMao.getAll(collegeId), customPool); - 异常处理:可以给每个异步任务添加异常兜底逻辑,避免单个任务失败导致整体阻塞:
CompletableFuture<List<Student>> studentFuture = CompletableFuture.supplyAsync(() -> studentMao.getAll(collegeId)) .exceptionally(e -> { log.error("获取学生列表失败", e); return Collections.emptyList(); // 返回空集合避免后续NPE }); - 线程安全:只要你的DAO实现是线程安全的(比如Spring的
JdbcTemplate、MyBatis的Mapper都是线程安全的),就不用担心多线程调用的问题,每个任务的结果会独立存储到对应的Future中。
三、代码优雅性优化
如果后续需要频繁同时使用这三个List,可以把它们封装成一个DTO类,让代码更整洁、可读性更强:
public class CampusDataDTO { private List<Student> students; private List<Department> departments; private List<College> colleges; // 全参构造器、Getter方法 public CampusDataDTO(List<Student> students, List<Department> departments, List<College> colleges) { this.students = students; this.departments = departments; this.colleges = colleges; } // Getters... }
之后不管是串行还是并行调用,最后都可以把结果封装到这个DTO里:
// 串行场景 CampusDataDTO campusData = new CampusDataDTO(students, departments, colleges); // 并行场景 CampusDataDTO campusData = new CampusDataDTO(studentFuture.join(), deptFuture.join(), collegeFuture.join());
总结
- 若数据量小、逻辑简单:直接用你的串行写法即可,成本最低;
- 若追求性能且调用独立:用
CompletableFuture并行调用,大幅缩短总耗时; - 始终注意异常处理,避免单个调用失败影响整个流程;
- 复杂场景下用DTO封装结果,提升代码可维护性。
内容的提问来源于stack exchange,提问作者Null Pointer
相关产品推荐
相关产品推荐

