You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用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(...);
        });
}

关键注意事项

  1. 移除外层@WithSession:否则所有Panache.withSession会复用已存在的全局Session,无法实现隔离。
  2. 避免复用外部Query:PanacheQuery与创建它的Session强绑定,必须在每个独立Session上下文内重新创建。
  3. 统一查询参数:确保每个并行任务的查询条件、分页参数完全一致,避免结果不一致。

内容的提问来源于stack exchange,提问作者Tiago Grosso

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 19:35:32