Contents

Hibernate 中JSON对象简介

1. 概述

一些项目可能需要将 JSON 对象保存在关系数据库中。

在本教程中,我们将了解如何获取 JSON 对象并将其保存在关系数据库中。

有几个可用的框架提供了这个功能,但我们将看一些只使用HibernateJackson 的简单、通用的选项。

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对象。