如何使用Reactive Panache并行执行多个数据库查询?
在Quarkus Panache Reactive中并行执行多个数据库查询的正确方式
问题根源
并行执行基于同一个PanacheQuery的操作(如list()、pageCount()、count())时触发java.lang.IllegalStateException: Illegal pop() with non-matching JdbcValuesSourceProcessingState,核心原因是:Reactive Session无法被多个Uni并行复用,且PanacheQuery会绑定到创建它的Session上下文。你之前的尝试失败,是因为复用了外层Session创建的Query,或外层@WithSession导致所有子操作复用同一个Session。
解决方案:每个并行任务独立创建Session与Query
必须让每个并行的Uni在独立Session内部创建自己的PanacheQuery,而非复用外部已创建的Query。以下是两种可行实现方式:
方式1:手动使用SessionFactory管理独立Session
@Inject SessionFactory sessionFactory; // 移除外层的@WithSession,避免全局Session干扰 public Uni<SearchSessionsResult> search(...) { // 封装查询逻辑,确保每个Session内创建独立Query Function<Session, Uni<List<Session>>> listTask = session -> session.find(Session.class, yourQueryCriteria) // 替换为你的查询条件 .page(Page.of(currentPage, pageSize)) // 保持分页参数一致 .list(); Function<Session, Uni<Integer>> pageCountTask = session -> session.find(Session.class, yourQueryCriteria) .page(Page.of(currentPage, pageSize)) .pageCount(); Function<Session, Uni<Long>> countTask = session -> session.find(Session.class, yourQueryCriteria).count(); return Uni.combine() .all() .unis( sessionFactory.openSession().chain(listTask).eventually(Session::close), sessionFactory.openSession().chain(pageCountTask).eventually(Session::close), sessionFactory.openSession().chain(countTask).eventually(Session::close) ) .combinedWith((entities, pageCount, totalEntries) -> { // 业务逻辑处理 return new SearchSessionsResult(entities, pageCount, totalEntries); }); }
方式2:使用Panache.withSession创建独立上下文
// 移除外层的@WithSession public Uni<SearchSessionsResult> search(...) { // 每个任务在独立Session内创建Query Supplier<Uni<List<Session>>> listTask = () -> Panache.find(Session.class, yourQueryCriteria) .page(Page.of(currentPage, pageSize)) .list(); Supplier<Uni<Integer>> pageCountTask = () -> Panache.find(Session.class, yourQueryCriteria) .page(Page.of(currentPage, pageSize)) .pageCount(); Supplier<Uni<Long>> countTask = () -> Panache.find(Session.class, yourQueryCriteria).count(); return Uni.combine() .all() .unis( Panache.withSession(listTask), Panache.withSession(pageCountTask), Panache.withSession(countTask) ) .combinedWith((entities, pageCount, totalEntries) -> { // 业务逻辑处理 return new SearchSessionsResult(...); }); }
关键注意事项
- 移除外层@WithSession:否则所有
Panache.withSession会复用已存在的全局Session,无法实现隔离。 - 避免复用外部Query:
PanacheQuery与创建它的Session强绑定,必须在每个独立Session上下文内重新创建。 - 统一查询参数:确保每个并行任务的查询条件、分页参数完全一致,避免结果不一致。
内容的提问来源于stack exchange,提问作者Tiago Grosso
相关产品推荐
相关产品推荐

