Java 使用 Hibernate 和 JPA 持久化 JSON 对象
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/40802656/
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
Persisting a JSON Object using Hibernate and JPA
提问by Fawzan
I am trying to store a JSON object in MySQL database in spring boot. I know I am doing something wrong but I a can't figure out what it is because I am fairly new to Spring.
我试图在春季启动时在 MySQL 数据库中存储一个 JSON 对象。我知道我做错了什么,但我无法弄清楚它是什么,因为我对 Spring 相当陌生。
I have a rest endpoint where I get the following JSON object (via HTTP PUT) and I need to store it in database so that the user can fetch it later (via HTTP GET).
我有一个休息端点,在那里我获得了以下 JSON 对象(通过 HTTP PUT),我需要将它存储在数据库中,以便用户可以稍后(通过 HTTP GET)获取它。
{
"A": {
"Name": "Cat",
"Age": "1"
},
"B": {
"Name": "Dog",
"Age": "2"
},
"C": {
"Name": "Horse",
"Age": "1"
}
}
Note that in the above case The numberofkeysin the object may vary, Due to that requirement I am using a HashMap
to catch the object in the controller.
请注意,在上述情况下,对象中的键数可能会有所不同,由于该要求,我使用 a来捕获控制器中的对象。HashMap
@RequestMapping(method = RequestMethod.POST)
public String addPostCollection(@RequestBody HashMap<String, Animal> hp) {
hp.forEach((x, y) -> {
postRepository.save(hp.get(x));
});
return "OK";
}
As you can see in the method, I can iterate the HashMap
and persist each Animal
object in db. But I am looking for a way to persist the entire HashMap
in a single record. I have did some reading and they suggest me to use a @ManyToMany
mapping.
正如您在方法中看到的,我可以迭代HashMap
并持久化Animal
数据库中的每个对象。但我正在寻找一种将整个HashMap
记录保存在单个记录中的方法。我做了一些阅读,他们建议我使用@ManyToMany
映射。
Can anyone point me in a direction to persist the HashMap
in a different way? (or is using the @ManyToMany
the only and right way to do this?)
任何人都可以指出我以HashMap
不同方式坚持的方向吗?(或者是使用@ManyToMany
唯一正确的方法来做到这一点?)
采纳答案by Vlad Mihalcea
This is a very common requirement, so I decided to write a very detailed article, about the best way to map JSON column types when using JPA and Hibernate.
这是一个非常普遍的需求,所以我决定写一篇非常详细的文章,介绍使用 JPA 和 Hibernate 时映射 JSON 列类型的最佳方法。
Maven dependency
Maven 依赖
The first thing you need to do is to set up the following Hibernate TypesMaven dependency in your project pom.xml
configuration file:
您需要做的第一件事是在您的项目配置文件中设置以下Hibernate TypesMaven 依赖项pom.xml
:
<dependency>
<groupId>com.vladmihalcea</groupId>
<artifactId>hibernate-types-52</artifactId>
<version>${hibernate-types.version}</version>
</dependency>
Domain model
领域模型
Let's assume you have the following entity:
假设您有以下实体:
@Entity(name = "Book")
@Table(name = "book")
@TypeDef(
typeClass = JsonBinaryType.class,
defaultForType = JsonNode.class
)
public class Book {
@Id
@GeneratedValue
private Long id;
@NaturalId
private String isbn;
@Column(columnDefinition = "jsonb")
private JsonNode properties;
//Getters and setters omitted for brevity
}
Notice the @TypeDef
is used to instruct Hibernate to map the JsonNode
object using the JsonBinaryType
offered by the Hibernate Types project.
注意@TypeDef
用于指示 HibernateJsonNode
使用JsonBinaryType
Hibernate Types 项目提供的映射对象。
Testing time
测试时间
Now, if you save an entity:
现在,如果您保存实体:
Book book = new Book();
book.setIsbn( "978-9730228236" );
book.setProperties(
HymansonUtil.toJsonNode(
"{" +
" \"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:
您还可以重新加载并修改它:
Session session = entityManager.unwrap( Session.class );
Book book = session
.bySimpleNaturalId( Book.class )
.load( "978-9730228236" );
LOGGER.info( "Book details: {}", book.getProperties() );
book.setProperties(
HymansonUtil.toJsonNode(
"{" +
" \"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
-- Book details: {"price":44.99,"title":"High-Performance Java Persistence","author":"Vlad Mihalcea","publisher":"Amazon"}
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
回答by Petre Popescu
You can use FasterXML (or similar) to parse the Json into an actual object (you need to define the class) and use Json.toJson(yourObj).toString()
to retrieve the Json String. It also simplifies working with the objects since your data class may also have functionality.
您可以使用 FasterXML(或类似的)将 Json 解析为实际对象(您需要定义类)并用于Json.toJson(yourObj).toString()
检索 Json 字符串。它还简化了对象的使用,因为您的数据类也可能具有功能。
回答by Peter ?ály
One animal is one record. You are saving more records, not one record. You can commit more records in one transaction. See: How to persist a lot of entities (JPA)
一只动物是一个记录。您正在保存更多记录,而不是一条记录。您可以在一个事务中提交更多记录。请参阅:如何持久化大量实体 (JPA)
回答by kaaas
Your JSON is well structered, so usually theres no need to persist the entire map in one single record. You won't be able to use the Hibernate/JPA query functions and a lot more.
您的 JSON 结构良好,因此通常无需将整个地图保存在单个记录中。您将无法使用 Hibernate/JPA 查询功能等等。
If you really want to persist the entire map in one single record, you could persist the map in its string representation and, as already proposed, use a JSON parser like Hymanson to rebuild your HashMap
如果您真的想将整个地图保存在一个单独的记录中,您可以将地图保存在其字符串表示中,并且正如已经提出的那样,使用像 Hymanson 这样的 JSON 解析器来重建您的 HashMap
@Entity
public class Animals {
private String animalsString;
public void setAnimalsString(String val) {
this.animalsString = val;
}
public String getAnimalsString() {
return this.animalsMap;
}
public HashMap<String, Animal> getAnimalsMap() {
ObjectMapper mapper = new ObjectMapper();
TypeReference<HashMap<String,Animal>> typeRef = new TypeReference<HashMap<String,Animal>>() {};
return mapper.readValue(animalsString, typeRef);
}
}
Your animal class:
你的动物类:
public class Animal {
private String name;
private int age;
/* getter and setter */
/* ... */
}
And you could change your controller method to
您可以将控制器方法更改为
@RequestMapping(method = RequestMethod.POST)
public String addPostCollection(@RequestBody String hp) {
Animals animals = new Animals();
animals.setAnimalsString(hp);
animalsRepository.save(hp);
return "OK";
}