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

如何在Liquibase与JPA实体类中正确配置JSON数据列?

问题:如何在Liquibase XML和JPA实体类中配置JSON类型列?

我想要创建一张包含名为data的JSON数据存储列的表,请问如何在Liquibase的XML文件中配置该列,以及如何在JPA实体类中进行对应编写?我目前的写法如下,但不确定是否正确:

Liquibase XML 代码:

<changeSet author="ABC" id="HUI">
    <createTable tableName="archived_table">
        <column autoIncrement="true" name="id" type="BIGINT">
            <constraints primaryKey="true"
                         primaryKeyName="archive_tablePK" />
        </column>
        <column name="created" type="TIMESTAMP(6)">
        </column>
        <column name="data" type="jsonb"/>
    </createTable>
</changeSet>

JPA 实体类代码:

@Entity
@Table(name = "archived_table")
public class ArchiveModel extends BaseModel{
    @Column(nullable = false)
    private JSONObject data;

    public ArchiveDataModel(
            JSONObject data,
    ){
        super();
        this.data=data;
    }

    public JSONObject getData() {
        return data;
    }

    public void setData(JSONObject data) {
        this.data = data;
    }
}

回答

一、Liquibase XML 配置部分

你的Liquibase配置基本正确,但有几个细节可以优化:

  1. jsonb是PostgreSQL专属的JSON类型,如果你用的是MySQL需要改成json,Oracle则用JSON,要根据数据库类型对应调整type属性值。
  2. 如果业务要求data列非空,建议在Liquibase中添加约束,和实体类的nullable=false对应:
<column name="data" type="jsonb">
    <constraints nullable="false"/>
</column>
  1. created列建议添加默认值(当前时间),更贴合业务逻辑:
<column name="created" type="TIMESTAMP(6)" defaultValueComputed="CURRENT_TIMESTAMP(6)">
</column>

二、JPA 实体类部分

你的实体类写法存在关键问题,直接使用JSONObject(不管是Fastjson还是Jackson的实现)无法被JPA正确持久化,需要做以下调整:

方案1:自定义JPA属性转换器

适合需要指定JSON库处理序列化/反序列化的场景:

  1. 先创建转换器类:
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.persistence.AttributeConverter;
import jakarta.persistence.Converter;
import java.io.IOException;

@Converter(autoApply = true)
public class JsonObjectConverter implements AttributeConverter<Object, String> {
    private static final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public String convertToDatabaseColumn(Object attribute) {
        try {
            return objectMapper.writeValueAsString(attribute);
        } catch (IOException e) {
            throw new IllegalArgumentException("无法将对象转为JSON字符串", e);
        }
    }

    @Override
    public Object convertToEntityAttribute(String dbData) {
        try {
            return objectMapper.readValue(dbData, Object.class);
        } catch (IOException e) {
            throw new IllegalArgumentException("无法将JSON字符串转为对象", e);
        }
    }
}
  1. 修改实体类:
@Entity
@Table(name = "archived_table")
public class ArchiveModel extends BaseModel {
    @Column(nullable = false, columnDefinition = "jsonb")
    @Convert(converter = JsonObjectConverter.class)
    private Object data; // 也可以用Map<String, Object>或者自定义DTO类

    // 构造方法名必须和实体类名一致,你的代码里写的ArchiveDataModel是错误的
    public ArchiveModel(Object data) {
        super();
        this.data = data;
    }

    // JPA要求实体类必须有无参构造方法
    public ArchiveModel() {
        super();
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }
}

方案2:用Hibernate原生JSON支持(基于Hibernate作为JPA实现)

Hibernate对JSON类型有原生支持,无需自定义转换器:

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import org.hibernate.annotations.JdbcTypeCode;
import org.hibernate.type.SqlTypes;

@Entity
@Table(name = "archived_table")
public class ArchiveModel extends BaseModel {
    @Column(nullable = false, columnDefinition = "jsonb")
    @JdbcTypeCode(SqlTypes.JSON)
    private Object data; // 可替换为Map<String, Object>或自定义DTO

    // 修正构造方法名,添加JPA必需的无参构造
    public ArchiveModel() {
        super();
    }

    public ArchiveModel(Object data) {
        super();
        this.data = data;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }
}

实体类的核心错误修正:

  1. 构造方法名错误:你写的ArchiveDataModel必须和实体类名ArchiveModel一致。
  2. 缺少无参构造:JPA强制要求实体类提供无参构造方法。
  3. 直接使用JSONObject无法被JPA正确映射,必须通过转换器或Hibernate原生注解处理序列化逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 14:45:32