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

Quarkus 3.5.0中如何用PanacheRepository异步调用存储过程?

在Quarkus 3.5.0 Reactive Hibernate Panache中异步调用存储过程(PanacheRepository模式)

问题根源

你之前的代码中,Uni.createFrom().emitter()的回调逻辑仍运行在IO线程上,而EntityManager的JDBC操作是阻塞性的,违反了Quarkus的IO线程非阻塞约束,因此触发BlockingOperationNotAllowedException。核心解决思路是将阻塞的数据库操作转移到工作线程执行。

可行解决方案

方法1:使用@Blocking注解自动调度到工作线程

在PanacheRepository的方法上添加@Blocking注解,Quarkus会自动将方法执行调度到工作线程,同时保持反应式的Uni返回类型。

import io.quarkus.hibernate.orm.panache.PanacheRepository;
import io.smallrye.mutiny.Uni;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import io.quarkus.vertx.Blocking;

@ApplicationScoped
public class YourEntityRepository implements PanacheRepository<YourEntity> {

    @PersistenceContext
    EntityManager entityManager;

    @Blocking
    public Uni<Integer> executeStoredProcedure() {
        // 执行更新类存储过程,返回受影响行数
        int affectedRows = entityManager.createNativeQuery("call procName(1, 2)", Integer.class)
                .executeUpdate();
        return Uni.createFrom().item(affectedRows);
    }
}

方法2:手动指定工作线程执行阻塞逻辑

如果不想依赖注解,可通过Uni的API手动将阻塞操作切换到工作线程,使用runSubscriptionOn绑定默认工作线程池:

import io.quarkus.hibernate.orm.panache.PanacheRepository;
import io.smallrye.mutiny.Uni;
import io.smallrye.mutiny.infrastructure.Infrastructure;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;

@ApplicationScoped
public class YourEntityRepository implements PanacheRepository<YourEntity> {

    @PersistenceContext
    EntityManager entityManager;

    public Uni<Integer> executeStoredProcedure() {
        return Uni.createFrom().item(() -> {
            // 此逻辑将在工作线程执行
            return entityManager.createNativeQuery("call procName(1, 2)", Integer.class)
                    .executeUpdate();
        }).runSubscriptionOn(Infrastructure.getDefaultWorkerPool());
    }
}

方法3:结合事务执行存储过程

若存储过程需要在事务上下文运行,可结合Panache的withTransaction方法,并指定工作线程:

public Uni<Integer> executeStoredProcedureInTransaction() {
    return withTransaction(() -> {
        int affectedRows = entityManager.createNativeQuery("call procName(1, 2)", Integer.class)
                .executeUpdate();
        return Uni.createFrom().item(affectedRows);
    }).runSubscriptionOn(Infrastructure.getDefaultWorkerPool());
}

处理返回结果集的存储过程

如果存储过程返回查询结果集(而非更新计数),将executeUpdate()替换为getResultList()即可:

@Blocking
public Uni<List<Integer>> queryStoredProcedureResults() {
    List<Integer> results = entityManager.createNativeQuery("call procName(1, 2)", Integer.class)
            .getResultList();
    return Uni.createFrom().item(results);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 19:16:28