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

如何用Quarkus Hibernate Reactive Panache创建SQL视图

在Quarkus Hibernate Reactive Panache中映射SQL视图

你之前的写法问题在于误用了@Entity注解(该注解用于映射数据库物理表),而SQL视图是只读逻辑结构,需要搭配Hibernate的@Immutable和@Subselect来实现,同时必须指定主键(Hibernate要求所有实体都具备唯一标识)。下面提供两种可行的解决方案:

方案1:逻辑视图(无需手动创建数据库视图)

这种方式不需要在数据库中提前创建视图,Hibernate会在查询时自动执行@Subselect中的SQL语句生成视图数据:

import io.quarkus.hibernate.reactive.panache.PanacheEntityBase;
import jakarta.persistence.Column;
import jakarta.persistence.Id;
import org.hibernate.annotations.Immutable;
import org.hibernate.annotations.Subselect;
import org.hibernate.annotations.Synchronize;

@Immutable // 标记为只读实体,禁止生成更新/插入/删除语句
@Subselect("SELECT i.id as invoice_id, i.appointment_ids FROM invoice i")
@Synchronize("invoice") // 可选:当invoice表数据变更时自动刷新视图缓存
public class BilledAppointments extends PanacheEntityBase {
    @Id // 必须指定主键,Hibernate要求实体有唯一标识
    @Column(name = "invoice_id")
    public Long invoiceId;

    @Column(name = "appointment_ids")
    public String appointmentsIds;
}

核心要点说明:

  • @Immutable:明确告知Hibernate该实体为只读,完全适配视图的不可修改特性。
  • @Subselect:定义视图的查询逻辑,相当于动态生成视图数据,无需数据库中存在物理视图。
  • @Synchronize:关联源表invoice,当源表数据更新时,自动清除视图实体的缓存,确保读取最新数据。
  • @Id:必须配置,这里用invoice_id作为主键(保证每行唯一),否则Hibernate会抛出实体无主键的异常。

方案2:映射物理数据库视图(提前创建视图)

如果需要在数据库层面创建物理视图(比如需要复杂SQL优化、权限控制),可以先手动创建视图,再映射实体:

1. 创建物理视图(可通过Quarkus的import.sql或Flyway/Liquibase脚本执行)

CREATE VIEW billed_appointments AS
SELECT i.id as invoice_id, i.appointment_ids FROM invoice i;

2. 实体映射代码

import io.quarkus.hibernate.reactive.panache.PanacheEntityBase;
import jakarta.persistence.Column;
import jakarta.persistence.Id;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import org.hibernate.annotations.Immutable;

@Entity
@Immutable
@Table(name = "billed_appointments") // 直接映射到已创建的物理视图
public class BilledAppointments extends PanacheEntityBase {
    @Id
    @Column(name = "invoice_id")
    public Long invoiceId;

    @Column(name = "appointment_ids")
    public String appointmentsIds;
}

使用方式

两种方案的使用逻辑和普通Panache实体完全一致,例如:

public Uni<List<BilledAppointments>> getAllBilledAppointments() {
    return BilledAppointments.listAll();
}

public Uni<BilledAppointments> findByInvoiceId(Long id) {
    return BilledAppointments.findById(id);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 08:45:46