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

如何用Spring Data JPA将嵌套JSON存储到MySQL数据库?

如何将复杂嵌套JSON存储到MySQL及嵌套元素类的处理方案

针对你遇到的复杂嵌套JSON存储问题,提供两种主流解决方案,同时明确嵌套元素类的处理方式:


方案一:关系型数据库规范存储(需创建嵌套实体类)

这种方式遵循数据库设计范式,将嵌套数据拆分为多个关联表,适合需要频繁查询、修改嵌套内部数据的场景。

1. 创建实体类

分别为甜甜圈(Donut)、面糊(Batter)、配料(Topping)创建带JPA注解的实体类,建立一对多关联:

Donut 实体类

@Entity
@Table(name = "donuts")
public class Donut {
    @Id
    private String id;
    private String type;
    private String name;
    private BigDecimal ppu;

    // 关联多个面糊,级联增删改
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "donut")
    private List<Batter> batters;

    // 关联多个配料,级联增删改
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "donut")
    private List<Topping> toppings;

    // 构造器、getter、setter 省略
}

Batter 实体类

@Entity
@Table(name = "batters")
public class Batter {
    @Id
    private String id;
    private String type;

    // 关联所属甜甜圈
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "donut_id")
    private Donut donut;

    // 构造器、getter、setter 省略
}

Topping 实体类

@Entity
@Table(name = "toppings")
public class Topping {
    @Id
    private String id;
    private String type;

    // 关联所属甜甜圈
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "donut_id")
    private Donut donut;

    // 构造器、getter、setter 省略
}

2. 创建Repository接口

为每个实体类创建Spring Data JPA Repository:

public interface DonutRepository extends JpaRepository<Donut, String> {}
public interface BatterRepository extends JpaRepository<Batter, String> {}
public interface ToppingRepository extends JpaRepository<Topping, String> {}

优势与劣势

  • 优势:符合数据库范式,支持复杂查询(如筛选使用巧克力面糊的甜甜圈),数据一致性强。
  • 劣势:需要维护多个实体和关联关系,存储时需处理对象间的关联绑定。

方案二:利用MySQL JSON字段存储(可选创建嵌套类)

MySQL 5.7及以上原生支持JSON类型,可直接将嵌套数据存入JSON字段,适合不需要频繁操作嵌套内部数据的场景。

方式1:直接存储JSON字符串(无需嵌套类)

仅创建Donut实体类,将batters和topping字段定义为字符串类型,指定数据库列类型为JSON:

@Entity
@Table(name = "donuts")
public class Donut {
    @Id
    private String id;
    private String type;
    private String name;
    private BigDecimal ppu;

    @Column(columnDefinition = "JSON")
    private String batters;

    @Column(columnDefinition = "JSON")
    private String toppings;

    // 构造器、getter、setter 省略
}

存储时需手动将嵌套对象序列化为JSON字符串,读取时再反序列化为对象,可使用Jackson或Gson工具类完成。

方式2:使用Converter自动转换(需创建嵌套类)

创建普通的嵌套类(无需@Entity注解),通过JPA Converter自动完成对象与JSON字符串的转换:

嵌套类定义

// 对应batters结构
public class Batters {
    private List<Batter> batter;
    // getter、setter 省略
}

public class Batter {
    private String id;
    private String type;
    // getter、setter 省略
}

public class Topping {
    private String id;
    private String type;
    // getter、setter 省略
}

创建Converter类

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

    @Override
    public String convertToDatabaseColumn(Batters batters) {
        try {
            return objectMapper.writeValueAsString(batters);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("Batters转JSON失败", e);
        }
    }

    @Override
    public Batters convertToEntityAttribute(String dbData) {
        try {
            return objectMapper.readValue(dbData, Batters.class);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("JSON转Batters失败", e);
        }
    }
}

@Converter(autoApply = true)
public class ToppingListConverter implements AttributeConverter<List<Topping>, String> {
    private final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public String convertToDatabaseColumn(List<Topping> toppings) {
        try {
            return objectMapper.writeValueAsString(toppings);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("Topping列表转JSON失败", e);
        }
    }

    @Override
    public List<Topping> convertToEntityAttribute(String dbData) {
        try {
            return objectMapper.readValue(dbData, new TypeReference<List<Topping>>() {});
        } catch (JsonProcessingException e) {
            throw new RuntimeException("JSON转Topping列表失败", e);
        }
    }
}

Donut实体类调整

@Entity
@Table(name = "donuts")
public class Donut {
    @Id
    private String id;
    private String type;
    private String name;
    private BigDecimal ppu;

    @Convert(converter = BattersConverter.class)
    private Batters batters;

    @Convert(converter = ToppingListConverter.class)
    private List<Topping> toppings;

    // 构造器、getter、setter 省略
}

优势与劣势

  • 优势:无需维护多表关联,实现简单,适合快速开发和嵌套数据结构多变的场景。
  • 劣势:嵌套内部数据的查询、修改性能较差,MySQL对JSON字段的索引支持有限(需通过生成列实现)。

关于是否需要为嵌套元素创建类的总结

  • 若选择关系型规范存储:需要创建对应嵌套元素的实体类(带@Entity注解),建立表关联。
  • 若选择JSON字段存储:
    • 直接存JSON字符串:无需创建嵌套类。
    • 使用Converter自动转换:需要创建普通嵌套类(无需@Entity注解),用于对象与JSON的转换。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 13:24:51