1. 概述
在某些项目中,我们可能需要将 JSON 对象存储到关系型数据库中。
本篇文章将介绍几种方式,帮助我们将 JSON 对象 持久化到关系型数据库中。
虽然有很多框架支持这一功能,但本文将聚焦于一些简单、通用的方案,使用 Hibernate、Jackson 以及 Hypersistence Utils 库来实现。
2. 依赖项
本教程使用 Hibernate Core 作为基础依赖:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.4.24.Final</version>
</dependency>
同时使用 Jackson 作为 JSON 处理库:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.3</version>
</dependency>
⚠️ 注意:这些方法并不局限于这两个库,你可以自由替换为其他 JPA 实现或 JSON 库。
3. 序列化与反序列化方法
最基础的做法是:在持久化前将 JSON 对象转换为字符串,读取时再将其转换回对象。
我们可以通过以下方式实现:
- 自定义序列化和反序列化方法
我们以一个 Customer
实体为例,包含姓名和一些客户属性(用 HashMap
表示):
@Entity
@Table(name = "Customers")
public class Customer {
@Id
private int id;
private String firstName;
private String lastName;
private String customerAttributeJSON;
@Convert(converter = HashMapConverter.class)
private Map<String, Object> customerAttributes;
}
我们选择将客户属性以 JSON 字符串的形式存储在 customerAttributeJSON
字段中,而不是使用关联表。✅ 这样可以简化数据库结构并提升查询性能。
3.1 序列化方法
public void serializeCustomerAttributes() throws JsonProcessingException {
this.customerAttributeJSON = objectMapper.writeValueAsString(customerAttributes);
}
你可以在每次设置属性时自动调用该方法,或手动在持久化前调用。
3.2 反序列化方法
public void deserializeCustomerAttributes() throws IOException {
this.customerAttributes = objectMapper.readValue(customerAttributeJSON,
new TypeReference<Map<String, Object>>() {});
}
3.3 使用示例
@Test
public void whenStoringAJsonColumn_thenDeserializedVersionMatches() {
Customer customer = new Customer();
customer.setFirstName("first name");
customer.setLastName("last name");
Map<String, Object> attributes = new HashMap<>();
attributes.put("address", "123 Main Street");
attributes.put("zipcode", 12345);
customer.setCustomerAttributes(attributes);
customer.serializeCustomerAttributes();
String serialized = customer.getCustomerAttributeJSON();
customer.setCustomerAttributeJSON(serialized);
customer.deserializeCustomerAttributes();
assertEquals(attributes, customer.getCustomerAttributes());
}
4. 属性转换器(Attribute Converter)
如果你使用的是 JPA 2.1 或更高版本,可以使用 AttributeConverter
来简化这个过程。
4.1 创建转换器
public class HashMapConverter implements AttributeConverter<Map<String, Object>, String> {
@Override
public String convertToDatabaseColumn(Map<String, Object> customerInfo) {
try {
return objectMapper.writeValueAsString(customerInfo);
} catch (final JsonProcessingException e) {
logger.error("JSON 写入失败", e);
return null;
}
}
@Override
public Map<String, Object> convertToEntityAttribute(String customerInfoJSON) {
try {
return objectMapper.readValue(customerInfoJSON,
new TypeReference<HashMap<String, Object>>() {});
} catch (final IOException e) {
logger.error("JSON 读取失败", e);
return null;
}
}
}
4.2 应用转换器
@Convert(converter = HashMapConverter.class)
private Map<String, Object> customerAttributes;
✅ 使用这种方式,Hibernate 会自动完成序列化与反序列化,无需手动调用方法。
5. 使用 Hypersistence Utils 库
Hypersistence Utils 是一个轻量级库,支持将 JSON 映射到多种数据库(如 H2、MySQL、Oracle 等)。
5.1 添加依赖
<dependency>
<groupId>io.hypersistence</groupId>
<artifactId>hypersistence-utils-hibernate-55</artifactId>
<version>3.8.1</version>
</dependency>
⚠️ 注意:Hibernate 版本不同需使用对应的依赖,如 Hibernate 6 使用
hypersistence-utils-hibernate-60
。
5.2 实体示例
@Entity
@TypeDef(name = "json", typeClass = JsonType.class)
public class Warehouse {
@Id
@GeneratedValue
private Long id;
private String name;
private String location;
@Type(type = "json")
@Column(columnDefinition = "json")
private Map<String, String> attributes = new HashMap<>();
}
✅ 使用 @TypeDef
定义类型别名,@Type
引用该类型,即可实现自动映射。
6. 使用 @JdbcTypeCode
注解(Hibernate 6+)
Hibernate 6 引入了 @JdbcTypeCode
注解,用于指定字段的 JDBC 类型。
6.1 示例
@Entity
public class Store {
@Id
@GeneratedValue
private Long id;
private String name;
private String location;
@JdbcTypeCode(SqlTypes.JSON)
private Map<String, String> attributes = new HashMap<>();
}
✅ 无需自定义转换器,也无需外部库,直接使用该注解即可实现 JSON 映射。
7. 将 JSON 映射到 @Embeddable
类(Hibernate 6+)
从 Hibernate 6 开始,我们可以将 JSON 映射到嵌入类(@Embeddable
)中。
⚠️ 目前仅支持 Oracle 和 PostgreSQL。
7.1 嵌入类定义
@Embeddable
public class Specification implements Serializable {
private int ram;
private int internalMemory;
private String processor;
// 构造器、getter、setter 省略
}
7.2 实体类中使用
@Entity
public class Phone {
@Id
@GeneratedValue
private Long id;
private String name;
@Embedded
@JdbcTypeCode(SqlTypes.JSON)
private Specification specification;
}
✅ 使用 @Embedded
+ @JdbcTypeCode(SqlTypes.JSON)
实现嵌入类的 JSON 映射。
8. 总结
本文介绍了多种使用 Hibernate 持久化 JSON 对象的方法:
- 手动序列化与反序列化
- 使用
AttributeConverter
简化流程 - 利用 Hypersistence Utils 库
- Hibernate 6 的
@JdbcTypeCode
注解 - 嵌入类的 JSON 映射(仅部分数据库支持)
✅ 推荐使用 @JdbcTypeCode
或 Hypersistence 库,代码更简洁,维护成本更低。
如需源码,请访问 GitHub 项目地址。