1. Overview
1.概述
Some projects may require JSON objects to be persisted in a relational database.
一些项目可能需要将JSON对象持久化在一个关系数据库中。
In this tutorial, we’ll see how to take a JSON object and persist it in a relational database.
在本教程中,我们将看到如何取一个JSON对象并将其持久化在一个关系数据库中。
There are several frameworks available that provide this functionality, but we will look at a few simple, generic options using only Hibernate and Jackson.
有几个框架可以提供这种功能,但我们将只使用Hibernate和Jackson来看一些简单、通用的选项。
2. Dependencies
2.依赖性
We’ll use the basic Hibernate Core dependency for this tutorial:
我们将在本教程中使用基本的Hibernate Core依赖性。
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.4.12.Final</version>
</dependency>
We’ll also be using Jackson as our JSON library:
我们还将使用Jackson作为我们的JSON库。
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.3</version>
</dependency>
Note that these techniques are not limited to these two libraries. We can substitute our favorite JPA provider and JSON library.
注意,这些技术并不限于这两个库。我们可以用我们最喜欢的JPA提供者和JSON库来代替。
3. Serialize and Deserialize Methods
3.序列化和反序列化方法
The most basic way to persist a JSON object in a relational database is to convert the object into a String before persisting it. Then, we convert it back into an object when we retrieve it from the database.
在关系型数据库中持久化JSON对象的最基本方法是:在持久化之前,将该对象转换为String。然后,当我们从数据库中检索它时,我们将其转换回对象。
We can do this in a few different ways.
我们可以通过几种不同的方式来做到这一点。
The first one we’ll look at is using custom serialize and deserialize methods.
我们要看的第一个问题是使用自定义的序列化和反序列化方法。
We’ll start with a simple Customer entity that stores the customer’s first and last name, as well as some attributes about that customer.
我们将从一个简单的Customer实体开始,它存储了客户的名字和姓氏,以及关于该客户的一些属性。
A standard JSON object would represent those attributes as a HashMap, so that’s what we’ll use here:
一个标准的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;
}
Rather than saving the attributes in a separate table, we are going to store them as JSON in a column in the Customers table. This can help reduce schema complexity and improve the performance of queries.
我们不把属性保存在一个单独的表中,而是把它们作为JSON存储在Customers表中的一个列中。这可以帮助减少模式的复杂性,提高查询的性能。
First, we’ll create a serialize method that will take our customerAttributes and convert it to a JSON string:
首先,我们将创建一个序列化方法,将我们的customerAttributes转换为JSON字符串。
public void serializeCustomerAttributes() throws JsonProcessingException {
this.customerAttributeJSON = objectMapper.writeValueAsString(customerAttributes);
}
We can call this method manually before persisting, or we can call it from the setCustomerAttributes method so that each time the attributes are updated, the JSON string is also updated.
我们可以在持久化之前手动调用这个方法,或者从setCustomerAttributes方法中调用这个方法,这样每次属性被更新时,JSON字符串也会被更新。
Next, we’ll create a method to deserialize the JSON string back into a HashMap object when we retrieve the Customer from the database. We can do that by passing a TypeReference parameter to readValue():
接下来,我们将创建一个方法,当我们从数据库检索Customer时,将JSON字符串反序列化为HashMap对象。我们可以通过向readValue()传递一个TypeReference参数来做到这一点。
public void deserializeCustomerAttributes() throws IOException {
this.customerAttributes = objectMapper.readValue(customerAttributeJSON,
new TypeReference<Map<String, Object>>() {});
}
Once again, there are a few different places that we can call this method from, but, in this example, we’ll call it manually.
再一次,我们可以从几个不同的地方调用这个方法,但是,在这个例子中,我们将手动调用它。
So, persisting and retrieving our Customer object would look something like this:
因此,持久化和检索我们的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. Attribute Converter
4.属性转换器
If we are using JPA 2.1 or higher, we can make use of AttributeConverters to streamline this process.
如果我们使用JPA 2.1或更高版本,我们可以利用AttributeConverters来简化这一过程。
First, we’ll create an implementation of AttributeConverter. We’ll reuse our code from earlier:
首先,我们将创建一个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,
new TypeReference<HashMap<String, Object>>() {});
} catch (final IOException e) {
logger.error("JSON reading error", e);
}
return customerInfo;
}
}
Next, we tell Hibernate to use our new AttributeConverter for the customerAttributes field, and we’re done:
接下来,我们告诉Hibernate对customerAttributes字段使用我们新的AttributeConverter,然后我们就完成了。
@Convert(converter = HashMapConverter.class)
private Map<String, Object> customerAttributes;
With this approach, we no longer have to manually call the serialize and deserialize methods since Hibernate will take care of that for us. We can simply save and retrieve the Customer object normally.
通过这种方法,我们不再需要手动调用序列化和反序列化方法,因为Hibernate将为我们解决这个问题。我们可以简单地保存和检索Customer对象。
5. Conclusion
5.结论
In this article, we’ve seen several examples of how to persist JSON objects using Hibernate and Jackson.
在这篇文章中,我们已经看到了几个关于如何使用Hibernate和Jackson来持久化JSON对象的例子。
Our first example looked at a simple, compatible method using custom serialize and deserialize methods. And second, we introduced AttributeConverters as a powerful way to simplify our code.
我们的第一个例子是使用自定义序列化和反序列化方法的简单、兼容的方法。其次,我们介绍了AttributeConverters,作为简化代码的一种强大方式。
As always, make sure to check out the source code for this tutorial over on Github.
一如既往,请确保查看本教程的源代码在Github上。