春のブートでMySQLデータベースにJSONオブジェクトを保存しようとしています。私は何か間違ったことをしているのを知っていますが、私は春にかなり新しいのでそれが何であるか理解できません。
(HTTP PUTを介して)次のJSONオブジェクトを取得するレストエンドポイントがあり、ユーザーが後で(HTTP GETを介して)フェッチできるように、データベースに保存する必要があります。
{
"A": {
"Name": "Cat",
"Age": "1"
},
"B": {
"Name": "Dog",
"Age": "2"
},
"C": {
"Name": "Horse",
"Age": "1"
}
}
上記の場合、オブジェクトのnumberofkeysが異なる場合があることに注意してください。その要件のため、HashMap
を使用してオブジェクトをキャッチしていますコントローラで。
@RequestMapping(method = RequestMethod.POST)
public String addPostCollection(@RequestBody HashMap<String, Animal> hp) {
hp.forEach((x, y) -> {
postRepository.save(hp.get(x));
});
return "OK";
}
メソッドで確認できるように、HashMap
を繰り返し、各Animal
オブジェクトをdbに永続化できます。しかし、HashMap
全体を1つのレコードに永続化する方法を探しています。私はいくつか読んだことがあり、@ManyToMany
マッピングを使用するよう勧めています。
誰かがHashMap
を別の方法で永続化する方向に私を向けることができますか? (または、@ManyToMany
を使用してこれを行う唯一の正しい方法は?)
これは非常に一般的な要件であるため、JPAとHibernateを使用するときにJSON列タイプをマップする最良の方法について、 非常に詳細な記事 と書くことにしました。
最初に行う必要があるのは、次のように設定することです Hibernate Types プロジェクトにMaven依存関係pom.xml
構成ファイル:
<dependency>
<groupId>com.vladmihalcea</groupId>
<artifactId>hibernate-types-52</artifactId>
<version>${hibernate-types.version}</version>
</dependency>
次のエンティティがあるとします。
@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
}
@TypeDef
は、Hibernateタイププロジェクトによって提供されるJsonNode
を使用してJsonBinaryType
オブジェクトをマップするようにHibernateに指示するために使用されます。
エンティティを保存すると、次のようになります。
Book book = new Book();
book.setIsbn( "978-9730228236" );
book.setProperties(
JacksonUtil.toJsonNode(
"{" +
" \"title\": \"High-Performance Java Persistence\"," +
" \"author\": \"Vlad Mihalcea\"," +
" \"publisher\": \"Amazon\"," +
" \"price\": 44.99" +
"}"
)
);
entityManager.persist( book );
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
)
また、それをロードして変更することもできます。
Session session = entityManager.unwrap( Session.class );
Book book = session
.bySimpleNaturalId( Book.class )
.load( "978-9730228236" );
LOGGER.info( "Book details: {}", book.getProperties() );
book.setProperties(
JacksonUtil.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がUPDATE
ステートメントの注意を払っています:
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
JSONは適切に構造化されているため、通常はマップ全体を1つのレコードに保持する必要はありません。 Hibernate/JPAクエリ関数などを使用できなくなります。
マップ全体を1つのレコードに永続化したい場合は、マップをその文字列表現に永続化し、すでに提案されているように、Jacksonなどの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);
}
}
あなたの動物のクラス:
public class Animal {
private String name;
private int age;
/* getter and setter */
/* ... */
}
そして、あなたはあなたのコントローラメソッドを
@RequestMapping(method = RequestMethod.POST)
public String addPostCollection(@RequestBody String hp) {
Animals animals = new Animals();
animals.setAnimalsString(hp);
animalsRepository.save(hp);
return "OK";
}
FasterXML(または同様の)を使用してJsonを実際のオブジェクトに解析し(クラスを定義する必要があります)、Json.toJson(yourObj).toString()
を使用してJson文字列を取得できます。また、データクラスにも機能があるため、オブジェクトの操作が簡単になります。
一匹は一記録です。 1つのレコードではなく、より多くのレコードを保存しています。 1つのトランザクションでより多くのレコードをコミットできます。参照: 多くのエンティティを永続化する方法(JPA)