正如我在this article中解釋的那樣,使用Hibernate持久化JSON對象非常容易。
您不必手動創建所有這些類型的,你可以通過Maven的中央使用以下依賴簡單地得到 他們:
<dependency>
<groupId>com.vladmihalcea</groupId>
<artifactId>hibernate-types-52</artifactId>
<version>${hibernate-types.version}</version>
</dependency>
欲瞭解更多信息,請查看hibernate-types open-source project。
現在來解釋它是如何工作的。
假設你有以下實體:
@Entity(name = "Book")
@Table(name = "book")
@TypeDef(
name = "jsonb-node",
typeClass = JsonNodeBinaryType.class
)
public class Book {
@Id
@GeneratedValue
private Long id;
@NaturalId
private String isbn;
@Type(type = "jsonb-node")
@Column(columnDefinition = "jsonb")
private JsonNode properties;
//Getters and setters omitted for brevity
}
請注意,在上面的代碼段兩件事情:
- 的
@TypeDef
用於定義一個新的自定義Hibernate類型,jsonb-node
這是由處理JsonNodeBinaryType
properties
屬性具有jsonb
列類型,它被映射爲Jackson JsonNode
JsonNodeBinaryType
的實現這樣的:
public class JsonNodeBinaryType
extends AbstractSingleColumnStandardBasicType<JsonNode> {
public JsonNodeBinaryType() {
super(
JsonBinarySqlTypeDescriptor.INSTANCE,
JsonNodeTypeDescriptor.INSTANCE
);
}
public String getName() {
return "jsonb-node";
}
}
的JsonBinarySqlTypeDescriptor
看起來如下:
public class JsonBinarySqlTypeDescriptor
extends AbstractJsonSqlTypeDescriptor {
public static final JsonBinarySqlTypeDescriptor INSTANCE =
new JsonBinarySqlTypeDescriptor();
@Override
public <X> ValueBinder<X> getBinder(
final JavaTypeDescriptor<X> javaTypeDescriptor
) {
return new BasicBinder<X>(javaTypeDescriptor, this) {
@Override
protected void doBind(
PreparedStatement st,
X value,
int index,
WrapperOptions options
) throws SQLException {
st.setObject(
index,
javaTypeDescriptor.unwrap(
value,
JsonNode.class,
options
),
getSqlType()
);
}
@Override
protected void doBind(
CallableStatement st,
X value,
String name,
WrapperOptions options
) throws SQLException {
st.setObject(
name,
javaTypeDescriptor.unwrap(
value,
JsonNode.class,
options
),
getSqlType()
);
}
};
}
}
的AbstractJsonSqlTypeDescriptor源代碼可以在this article可視化。現在
,所述JsonNodeTypeDescriptor
是負責轉換成JsonNode
可能由潛在的JDBC驅動結合參數或從底層ResultSet
從JSON對象提取過程中可以使用各種表示。
public class JsonNodeTypeDescriptor
extends AbstractTypeDescriptor<JsonNode> {
public static final JsonNodeTypeDescriptor INSTANCE =
new JsonNodeTypeDescriptor();
public JsonNodeTypeDescriptor() {
super(
JsonNode.class,
new MutableMutabilityPlan<JsonNode>() {
@Override
protected JsonNode deepCopyNotNull(
JsonNode value
) {
return JacksonUtil.clone(value);
}
}
);
}
@Override
public boolean areEqual(JsonNode one, JsonNode another) {
if (one == another) {
return true;
}
if (one == null || another == null) {
return false;
}
return
JacksonUtil.toJsonNode(
JacksonUtil.toString(one)
).equals(
JacksonUtil.toJsonNode(
JacksonUtil.toString(another)
)
);
}
@Override
public String toString(JsonNode value) {
return JacksonUtil.toString(value);
}
@Override
public JsonNode fromString(String string) {
return JacksonUtil.toJsonNode(string);
}
@SuppressWarnings({ "unchecked" })
@Override
public <X> X unwrap(
JsonNode value,
Class<X> type,
WrapperOptions options
) {
if (value == null) {
return null;
}
if (String.class.isAssignableFrom(type)) {
return (X) toString(value);
}
if (JsonNode.class.isAssignableFrom(type)) {
return (X) JacksonUtil.toJsonNode(toString(value));
}
throw unknownUnwrap(type);
}
@Override
public <X> JsonNode wrap(X value, WrapperOptions options) {
if (value == null) {
return null;
}
return fromString(value.toString());
}
}
就是這樣!現在
,如果保存實體:
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);
休眠會生成以下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/\"" +
"}"
)
);
休眠正在爲您的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
所有代碼在GitHub上都可用。
「整個HashMap在單個記錄中」?或者單個數據庫事務中的整個hashmap? –
我的意思是單一記錄。 – Fawzan