如何使用 JPA 和 Hibernate 将 MySQL JSON 列映射到 Java 实体属性
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/44308167/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to map a MySQL JSON column to a Java entity property using JPA and Hibernate
提问by Heril Muratovic
I have MySQL column declared as type JSONand I have problems to map it with Jpa/Hibernate. I'm using Spring Boot on back-end.
我将 MySQL 列声明为JSON类型,并且在将其映射到 Jpa/Hibernate 时遇到问题。我在后端使用 Spring Boot。
Here is small part of my code:
这是我的代码的一小部分:
@Entity
@Table(name = "some_table_name")
public class MyCustomEntity implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(name = "json_value")
private JSONArray jsonValue;
The program returns me an error and tells me that I can't map the column.
该程序返回一个错误并告诉我我无法映射该列。
In mysql table the column is defined as:
在 mysql 表中,列定义为:
json_value JSON NOT NULL;
json_value JSON 非空;
采纳答案by Heril Muratovic
I prefer to do this way:
我更喜欢这样做:
- Creating converter (attribute converter) from Map to String and vice versa.
- Using Map to map mysql JSON column type in domain (entity) class
- 创建从 Map 到 String 的转换器(属性转换器),反之亦然。
- 使用Map映射域(实体)类中的mysql JSON列类型
The code is bellow.
代码如下。
JsonToMapConverted.java
JsonToMapConverted.java
@Converter
public class JsonToMapConverter
implements AttributeConverter<String, Map<String, Object>>
{
private static final Logger LOGGER = LoggerFactory.getLogger(JsonToMapConverter.class);
@Override
@SuppressWarnings("unchecked")
public Map<String, Object> convertToDatabaseColumn(String attribute)
{
if (attribute == null) {
return new HashMap<>();
}
try
{
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(attribute, HashMap.class);
}
catch (IOException e) {
LOGGER.error("Convert error while trying to convert string(JSON) to map data structure.");
}
return new HashMap<>();
}
@Override
public String convertToEntityAttribute(Map<String, Object> dbData)
{
try
{
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString(dbData);
}
catch (JsonProcessingException e)
{
LOGGER.error("Could not convert map to json string.");
return null;
}
}
}
Part of domain (entity-mapping) class
域(实体映射)类的一部分
...
@Column(name = "meta_data", columnDefinition = "json")
@Convert(attributeName = "data", converter = JsonToMapConverter.class)
private Map<String, Object> metaData = new HashMap<>();
...
This solution perfectly works for me.
这个解决方案非常适合我。
回答by Songle Bao
Heril Muratovic's answeris good, but I think the JsonToMapConverter
should implement AttributeConverter<Map<String, Object>, String>
, not AttributeConverter<String, Map<String, Object>>
. Here is the code that works for me
Heril Muratovic 的回答很好,但我认为JsonToMapConverter
应该实现AttributeConverter<Map<String, Object>, String>
,而不是AttributeConverter<String, Map<String, Object>>
。这是对我有用的代码
@Slf4j
@Converter
public class JsonToMapConverter implements AttributeConverter<Map<String, Object>, String> {
@Override
@SuppressWarnings("unchecked")
public Map<String, Object> convertToEntityAttribute(String attribute) {
if (attribute == null) {
return new HashMap<>();
}
try {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(attribute, HashMap.class);
} catch (IOException e) {
log.error("Convert error while trying to convert string(JSON) to map data structure.", e);
}
return new HashMap<>();
}
@Override
public String convertToDatabaseColumn(Map<String, Object> dbData) {
try {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.writeValueAsString(dbData);
} catch (JsonProcessingException e) {
log.error("Could not convert map to json string.", e);
return null;
}
}
}
回答by Vlad Mihalcea
As I explained in this article, it's very easy to persist JSON objects using Hibernate.
正如我在本文中解释的那样,使用 Hibernate 保留 JSON 对象非常容易。
You don't have to create all these types manually, you can simply get them via Maven Central using the following dependency:
<dependency> <groupId>com.vladmihalcea</groupId> <artifactId>hibernate-types-52</artifactId> <version>${hibernate-types.version}</version> </dependency>
For more info, check out the hibernate-types open-source project.
您不必手动创建所有这些类型,您可以使用以下依赖项通过 Maven Central 轻松获取它们:
<dependency> <groupId>com.vladmihalcea</groupId> <artifactId>hibernate-types-52</artifactId> <version>${hibernate-types.version}</version> </dependency>
有关更多信息,请查看hibernate-types 开源项目。
Now, to explain how it all works.
现在,解释这一切是如何运作的。
Assuming you have the following entity:
假设您有以下实体:
@Entity(name = "Book")
@Table(name = "book")
@TypeDef(
name = "json",
typeClass = JsonStringType.class
)
public class Book {
@Id
@GeneratedValue
private Long id;
@NaturalId
private String isbn;
@Type(type = "json")
@Column(columnDefinition = "json")
private String properties;
//Getters and setters omitted for brevity
}
Notice two things in the code snippet above:
请注意上面代码片段中的两件事:
- the
@TypeDef
is used to define a new custom Hibernate Type,json
which is handled by theJsonStringType
- the
properties
attribute has ajson
column type and it's mapped as aString
- 的
@TypeDef
用于定义新的自定义休眠类型,json
这是由处理JsonStringType
- 该
properties
属性有一个json
列类型,它被映射为String
That's it!
而已!
Now, if you save an entity:
现在,如果您保存实体:
Book book = new Book();
book.setIsbn("978-9730228236");
book.setProperties(
"{" +
" \"title\": \"High-Performance Java Persistence\"," +
" \"author\": \"Vlad Mihalcea\"," +
" \"publisher\": \"Amazon\"," +
" \"price\": 44.99" +
"}"
);
entityManager.persist(book);
Hibernate is going to generate the following SQL statement:
Hibernate 将生成以下 SQL 语句:
INSERT INTO
book
(
isbn,
properties,
id
)
VALUES
(
'978-9730228236',
'{"title":"High-Performance Java Persistence","author":"Vlad Mihalcea","publisher":"Amazon","price":44.99}',
1
)
And you can also load it back and modify it:
您还可以重新加载并修改它:
Book book = entityManager
.unwrap(Session.class)
.bySimpleNaturalId(Book.class)
.load("978-9730228236");
book.setProperties(
"{" +
" \"title\": \"High-Performance Java Persistence\"," +
" \"author\": \"Vlad Mihalcea\"," +
" \"publisher\": \"Amazon\"," +
" \"price\": 44.99," +
" \"url\": \"https://www.amazon.com/High-Performance-Java-Persistence-Vlad-Mihalcea/dp/973022823X/\"" +
"}"
);
Hibernate taking caare of the UPDATE
statement for you:
HibernateUPDATE
为您处理声明:
SELECT b.id AS id1_0_
FROM book b
WHERE b.isbn = '978-9730228236'
SELECT b.id AS id1_0_0_ ,
b.isbn AS isbn2_0_0_ ,
b.properties AS properti3_0_0_
FROM book b
WHERE b.id = 1
UPDATE
book
SET
properties = '{"title":"High-Performance Java Persistence","author":"Vlad Mihalcea","publisher":"Amazon","price":44.99,"url":"https://www.amazon.com/High-Performance-Java-Persistence-Vlad-Mihalcea/dp/973022823X/"}'
WHERE
id = 1
All code avilable on GitHub.
所有代码都可在GitHub 上使用。
回答by J. Wang
If the values inside your json array are simple strings you can do this:
如果您的 json 数组中的值是简单的字符串,您可以这样做:
@Type( type = "json" )
@Column( columnDefinition = "json" )
private String[] jsonValue;
回答by user1686407
For anyone can't make @J. Wang answer work :
对于任何人都无法制作@J。王回答工作:
Try add this dependency(it's for hibernate 5.1 and 5.0, other version check here)
尝试添加此依赖项(适用于 hibernate 5.1 和 5.0,其他版本在此处检查)
<dependency>
<groupId>com.vladmihalcea</groupId>
<artifactId>hibernate-types-5</artifactId>
<version>1.2.0</version>
</dependency>
And add this line to the entity
并将这一行添加到实体
@TypeDef(name = "json", typeClass = JsonStringType.class)
So full version of the entity class :
实体类的完整版本:
@Entity
@Table(name = "some_table_name")
@TypeDef(name = "json", typeClass = JsonStringType.class)
public class MyCustomEntity implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Type( type = "json" )
@Column( columnDefinition = "json" )
private List<String> jsonValue;
}
I test the code with spring boot 1.5.9 and hibernate-types-5 1.2.0 .
我使用 spring boot 1.5.9 和 hibernate-types-5 1.2.0 测试代码。