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

Quarkus Panache+PostgreSQL:JSONB存储转义问题求助

Quarkus Panache + PostgreSQL JSONB 无转义存储问题

问题场景

我在开发Quarkus Panache结合PostgreSQL的项目时,尝试将JSON数据以JSONB格式存储,但插入数据时JSON会被自动转义,导致数据库中存储的是带转义符的字符串,无法正常执行PostgreSQL的JSON查询。

当前插入代码

JsonObject jsonObject = Json.createObjectBuilder()
        .add("name", "John")
        .add("age", 30)
        .add("city", "New York")
        .build();
String jsonString = jsonObject.toString(); // Convert JsonObject to JSON String
return update("update OfferEntity o set o.items = ?1",  jsonString).onItem().transform(ignored -> offer);

数据库实际存储结果

"{\"name\":\"John\",\"age\":30,\"city\":\"New York\"}"

期望存储格式

{"name":"John","age":30,"city":"New York"}

原实体类代码

@Entity
@Table(name = "offering")
@Cacheable
@WithSession
public class OfferEntity extends PanacheEntityBase {

    @JdbcTypeCode(SqlTypes.JSON)
    @Column(name = "items", columnDefinition = "jsonb", insertable = false, updatable = false)
    private String items;

    public String getItems() {
        return items;
    }

    public void setItems(String items) {
        this.items = items;
    }
}

已尝试的无效方案

我试过两种修改实体类的方式,但结果还是一样,数据库中依然是转义后的格式:

方案1:使用自定义实体类

自定义Item类:

public class Item implements Serializable {
    private String name;
    private int age;
    private String city;// 已添加getter和setter
}

修改OfferEntity的items字段:

@JdbcTypeCode(SqlTypes.JSON)
@Column(name = "items", columnDefinition = "jsonb", insertable = false, updatable = false)
private Item items;

public Item getItems() {
    return items;
}

public void setItems(Item items) {
    this.items = items;
}

方案2:使用Map类型

修改OfferEntity的items字段:

@JdbcTypeCode(SqlTypes.JSON)
@Column(name = "items", columnDefinition = "jsonb", insertable = false, updatable = false)
private Map<String, String> items;

public Map<String, String> getItems() {
    return items;
}

public void setItems(Map<String, String> items) {
    this.items = items;
}

当前使用Hibernate版本为6.2.7 final,这会不会是Hibernate的Bug?


解决方案

1. 移除实体类字段的insertable = false, updatable = false配置

你当前的@Column注解里设置了insertable = false, updatable = false,这会让Hibernate跳过对该字段的自动持久化处理,导致你手动用JPQL更新时,直接把字符串当作普通文本插入,从而被转义。

修改后的字段注解:

@JdbcTypeCode(SqlTypes.JSON)
@Column(name = "items", columnDefinition = "jsonb")
private String items;

2. 避免手动转JSON字符串,直接使用实体类赋值

不要手动把JsonObject转成字符串再通过JPQL更新,而是直接给实体类的items字段赋值,让Hibernate自动处理JSON序列化:

JsonObject jsonObject = Json.createObjectBuilder()
        .add("name", "John")
        .add("age", 30)
        .add("city", "New York")
        .build();
offer.setItems(jsonObject.toString()); // 直接赋值给实体字段
offer.persistOrUpdate(); // 使用Panache的持久化方法
return offer;

3. 若使用自定义实体类/Map类型

确保移除insertable = false, updatable = false,然后直接赋值对象/Map,Hibernate会自动序列化为JSONB:

Item item = new Item();
item.setName("John");
item.setAge(30);
item.setCity("New York");
offer.setItems(item);
offer.persistOrUpdate();
return offer;

4. 若必须使用JPQL更新

如果一定要用JPQL的update语句,需要让参数以JSON类型传递,而不是字符串:

JsonObject jsonObject = Json.createObjectBuilder()
        .add("name", "John")
        .add("age", 30)
        .add("city", "New York")
        .build();
// 使用EntityManager指定参数为JSON类型
return getEntityManager()
        .createQuery("update OfferEntity o set o.items = ?1")
        .setParameter(1, jsonObject, JsonType.INSTANCE)
        .executeUpdate();

关键原因

问题核心是insertable = false, updatable = false导致Hibernate不识别该字段为JSON类型,手动插入字符串时被当作普通文本处理,加上转义符。移除这个配置后,Hibernate会根据@JdbcTypeCode(SqlTypes.JSON)和columnDefinition = "jsonb"自动处理JSON的序列化和反序列化,避免转义。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 19:52:02