Hibernate 中JSON对象简介
1. 概述
一些项目可能需要将 JSON 对象保存在关系数据库中。
在本教程中,我们将了解如何获取 JSON 对象并将其保存在关系数据库中。
有几个可用的框架提供了这个功能,但我们将看一些只使用Hibernate 和Jackson 的简单、通用的选项。
2. 依赖
我们将在 本教程中使用基本的 Hibernate Core 依赖项:
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.4.0.Final</version>
</dependency>
我们还将使用Jackson 作为我们的 JSON 库:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.0</version>
</dependency>
**请注意,这些技术不限于这两个库。**我们可以替换我们最喜欢的 JPA 提供程序和 JSON 库。
3. 序列化和反序列化方法
在关系数据库中持久化 JSON 对象的最基本方法是在持久化对象之前将其转换为string。然后,当我们从数据库中检索它时,我们将它转换回一个对象。
我们可以通过几种不同的方式做到这一点。
我们将看到的第一个是使用自定义序列化和反序列化方法。
我们将从一个简单的Customer实体开始,该实体存储客户的名字和姓氏,以及有关该客户的一些属性。
一个标准的 JSON 对象会将这些属性表示为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 存储在Customers表的列中。这有助于降低架构复杂性并提高查询性能。
首先,我们将创建一个序列化方法,该方法将获取我们的customerAttributes并将其转换为 JSON 字符串:
public void serializeCustomerAttributes() throws JsonProcessingException {
this.customerAttributeJSON = objectMapper.writeValueAsString(customerAttributes);
}
我们可以在持久化之前手动调用这个方法,也可以从setCustomerAttributes方法中调用,这样每次更新属性时,JSON 字符串也会更新。
接下来,当我们从数据库中检索Customer时,我们将创建一个将 JSON 字符串反序列化回HashMap对象的方法:
public void deserializeCustomerAttributes() throws IOException {
this.customerAttributes = objectMapper.readValue(customerAttributeJSON, HashMap.class);
}
再一次,我们可以从几个不同的地方调用这个方法,但是,在这个例子中,我们将手动调用它。
因此,持久化和检索我们的Customer对象看起来像这样:
@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. 属性转换器
如果我们使用 JPA 2.1 或更高版本,我们可以使用AttributeConverters来简化这个过程。
首先,我们将创建AttributeConverter的实现。我们将重用之前的代码:
public class HashMapConverter implements AttributeConverter<Map<String, Object>, String> {
@Override
public String convertToDatabaseColumn(Map<String, Object> customerInfo) {
String customerInfoJson = null;
try {
customerInfoJson = objectMapper.writeValueAsString(customerInfo);
} catch (final JsonProcessingException e) {
logger.error("JSON writing error", e);
}
return customerInfoJson;
}
@Override
public Map<String, Object> convertToEntityAttribute(String customerInfoJSON) {
Map<String, Object> customerInfo = null;
try {
customerInfo = objectMapper.readValue(customerInfoJSON, Map.class);
} catch (final IOException e) {
logger.error("JSON reading error", e);
}
return customerInfo;
}
}
接下来,我们告诉 Hibernate为customerAttributes字段使用我们的新AttributeConverter,我们就完成了:
@Convert(converter = HashMapConverter.class)
private Map<String, Object> customerAttributes;
使用这种方法,我们不再需要手动调用序列化和反序列化方法,因为 Hibernate 会为我们处理这些。我们可以简单地正常保存和检索Customer对象。