μλ νμΈμ. Hibernate Reactiveλ μ¬μ©μ μ μ UserTypeμ μ§μν©λκΉ? Postgres JSONB Typeμ μ¬μ©νκ³ μΆκ³ Hibernateμ AbstractSingleColumnStandardBasicType κΈ°λ°μΌλ‘ μ¬μ©μ μ μ μ νμ λΉλνλ λ€μ λΌμ΄λΈλ¬λ¦¬ https://github.com/vladmihalcea/hibernate-types λ₯Ό μ¬μ©νκ³ μμμ΅λλ€. λΆννλ Hibernateμμ Hibernate Reactiveλ‘ μ΄λνλ κ²λ§μΌλ‘λ μ΄λ¬ν μ νμ μ¬μ©νλ μ΄μ μν°ν°μμ νμ nullμ λλ€. λμμΌλ‘ Hibernateμ UserType μ λν JSONB Postgres μ§μμ ꡬμΆνλ μ΄ κΈ°μ¬ λ₯Ό μ°Ύμμ΅λλ€. νμ¬ μ¬μ©μ μ μ μ νμ μ μνκ³ Hibernate Reactiveλ₯Ό μ¬μ©νλ κ²κ³Ό κ΄λ ¨νμ¬ μλ €μ§ μ ν μ¬νμ΄ μμ΅λκΉ?
μλ
νμΈμ, ν΄λΉ μΈν°νμ΄μ€κ° JDBCμ μ°κ²°λμ΄ μκΈ° λλ¬Έμ UserType
ν
μ€νΈνμ§ μμμ΅λλ€. (μμΉμ μΌλ‘λ λλΆλΆ μλνλλ‘ λ§λ€ μ μμ΅λλ€.)
λμ μ¬λλ€μ΄ JPA λ³νκΈ°λ₯Ό μ¬μ©ν μ μλ€λ κ²μ΄ μ μκ°μ΄μμ΅λλ€. λλ κ·Έκ²μ ν μ€νΈνκ³ AFAIKκ° μλν©λλ€. λΉμ μ κ·Έκ²μ μλ νμ΅λκΉ?
UserTypeμ μ¬μ©νμ¬ λΉ λ₯Έ ν μ€νΈλ₯Ό μλνμ§λ§ 쿼리λ₯Ό μ€νν λ PgClientμμ μμΈκ° λ°μνκΈ° λλ¬Έμ μλνμ§ μλ κ² κ°μ΅λλ€.
UserTypeμ μ¬μ©νμ¬ λΉ λ₯Έ ν μ€νΈλ₯Ό μλνμ§λ§ 쿼리λ₯Ό μ€νν λ PgClientμμ μμΈκ° λ°μνκΈ° λλ¬Έμ μλνμ§ μλ κ² κ°μ΅λλ€.
κ·Έλ¬λ κ·Έκ²μ μ°λ¦¬μ κ°μ§ JDBC κ³μΈ΅μ΄ λΆμμ νκΈ° λλ¬ΈμΌ μ μμ΅λλ€. (μΌλΆ ꡬνλμ§ μμ λ©μλ.)
λͺ νννκΈ° μν΄ vlad λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©νμ¬ μμ λ₯Ό μλνμ΅λλ€.
@TypeDefs({
@TypeDef(name = "json", typeClass = JsonStringType.class),
@TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
})
@Entity(name="GuineaPig")
@Table(name="Pig")
public static class GuineaPig {
<strong i="6">@Id</strong>
private Integer id;
private String name;
@Type(type = "jsonb")
@Column(columnDefinition = "jsonb")
private Location location;
μ΄κ²μ μ€λ₯μ λλ€:
Caused by: io.vertx.core.impl.NoStackTraceThrowable: Parameter at position[0] with class = [com.fasterxml.jackson.databind.node.ObjectNode] and value = [{"country":"UK","city":"Gotham"}] can not be coerced to the expected class = [java.lang.Object] for encoding.
λ°μν pg ν΄λΌμ΄μΈνΈλ λ€λ₯Έ μ νμ μ¬μ©νμ¬ JSONμΌλ‘ λ³ννλ κ² κ°μ΅λλ€.
@gavinking pg-client μ νμ λν΄ μΌμ’ μ 맀νμ μ§μν΄μΌ ν©λκΉ?
JSON (io.reactiverse.pgclient.data.Json)
JSONB (io.reactiverse.pgclient.data.Json)
POINT (io.reactiverse.pgclient.data.Point)
LINE (io.reactiverse.pgclient.data.Line)
LSEG (io.reactiverse.pgclient.data.LineSegment)
BOX (io.reactiverse.pgclient.data.Box)
PATH (io.reactiverse.pgclient.data.Path)
POLYGON (io.reactiverse.pgclient.data.Polygon)
CIRCLE (io.reactiverse.pgclient.data.Circle)
ν΄λΌμ΄μΈνΈκ° io.reactiverse.pgclient.data.Json
μ νμ κ°μ²΄λ₯Ό κΈ°λνκ³ μλ€κ³ μκ°ν©λλ€. κ·Έλλ UserType
μ¬λ°λ₯΄κ² μ²λ¦¬νλ κ² κ°μ΅λλ€.
λ°λ‘ μμ λ΄ λκΈμμ λ΄κ° μλ―Έν λ°μ λλ€. μ°λ¦¬μ JDBC μ΄λν°λ JDBCμ μμ ν ꡬνμ κ°κΉμ§λ μμΌλ©°, λλ κ·Έλ€μ΄ κ²°μ½ κ·Έλ μ§ μμ κ°λ₯μ±μ΄ λ§€μ° λλ€κ³ λ΄ λλ€. νΉν "μ΄κ΅μ μΈ" JDBC μ νμ κ²½μ° μ΄λ₯Ό Vert.x APIμ 맀ννλ κ²μ΄ μλΉν μ΄λ €μΈ μ μμ΅λλ€.
pg-client μ νμ λν΄ μΌμ’ μ 맀νμ μ§μν΄μΌ ν©λκΉ?
κΈμμ, λ§μ½ κ·Έκ²μ΄ ν©λ¦¬μ μΌλ‘ μ¬μ΄ μΌμ΄λΌλ©΄ λ§μ΄μ£ .
κ·Έλ¬λ κ·Έλ μ§ μλ€λ©΄ μλ§λ UserType
κ° μ¬κΈ°μμ μ¬λ°λ₯Έ μΆμνκ° μλλΌλ μ μ κ³ λ €νκ³ λ€λ₯Έ μ κ·Ό λ°©μμ μ°ΎμμΌ ν©λλ€.
λ΄ λ§μ, κΈ°μ‘΄μ UserType
λμ°ν μΌμ νμ§ μκ³ μλνλλ‘ λ§λ€ μ μμ μ λλ‘λ§ μλνλλ‘ ν©μλ€. λ§μ΄κ·Έλ μ΄μ
μ΄ λ μ¬μμ§λλ€. κ·Έλ¬λ λλ μ°λ¦¬κ° κ·Έκ³³μμ μ€μ λ‘ κ°λ₯ν κ²μ λν νκ³μ 빨리 λΆλͺν κ°λ₯μ±μ΄ μλ€κ³ μκ°ν©λλ€.
λ΄κ° λ΄μ€κ²
λ΄κ° λ΄μ€κ²
첫 λ²μ§Έ λ¨κ³λ‘ κΈ°λ³Έ κ°λ
μ΄ μλνλμ§ νμΈνκΈ° μν΄ λ©μ§ λ°μ΄ν°λ² μ΄μ€ μ νμ μ¬μ©νμ§ μλ μμ ν νλ²ν UserType
μ λν ν
μ€νΈλ₯Ό μΆκ°ν΄μΌ ν©λλ€. ).
@gavinking μλμ Hibernate Types λΌμ΄λΈλ¬λ¦¬μ ν¨κ» Hibernateλ₯Ό μ¬μ©νκ³ μκΈ° λλ¬Έμ μμ§ Converterλ₯Ό ν μ€νΈνμ§ μμμ΅λλ€. κ·Έλ¬λ λ³νκΈ°λ₯Ό μ¬μ©νλΌλ μ μμ κ²°κ΅ μΌλ° Postgres Text/Varcharλ₯Ό Postgres JSONB μ νμ΄ μλ DBμ λ£μ κ²μμ μλ―Έν©λλ€.
@gavinking μλμ Hibernate Types λΌμ΄λΈλ¬λ¦¬μ ν¨κ» Hibernateλ₯Ό μ¬μ©νκ³ μκΈ° λλ¬Έμ μμ§ Converterλ₯Ό ν μ€νΈνμ§ μμμ΅λλ€. κ·Έλ¬λ λ³νκΈ°λ₯Ό μ¬μ©νλΌλ μ μμ κ²°κ΅ μΌλ° Postgres Text/Varcharλ₯Ό Postgres JSONB μ νμ΄ μλ DBμ λ£μ κ²μμ μλ―Έν©λλ€.
λͺ νν νκΈ° μν΄: Java λλ λ°μ΄ν°λ² μ΄μ€μ μ΄λ€ μ νμ΄ μλμ§ μ°λ €νκ³ μμ΅λκΉ? μ¬κΈ°μλ λ κ°μ§ λ€λ₯Έ μ μ΄ μμ΅λλ€.
JSONB
λ₯Ό μ¬μ©νλ κ²μ΄μ§λ§ μμΉμ μΌλ‘ λλΌμ΄λ²κ° λ¬Έμμ΄μ ν΄λΉ μ νμΌλ‘ ν¬λͺ
νκ² λ³νν μ μλ€κ³ μκ°νμ κ²μ
λλ€. (νμ€νμ§ μμ΅λλ€. μλν μ μ΄ μμ΅λλ€.)io.reactiverse.pgclient.data.Json
λ₯Ό λͺ¨λΈμ Java μ νμΌλ‘ μ¬μ©νλ κ²μ
λλ€. κ·Έκ²μ μμ ν λ€λ₯Έ λ¬Έμ μ΄λ©° μ€μ λ‘ UserType
μ κ°μ κ²μ΄ νμν©λλ€.@gavinking
Postgres JSONB
μ νμ μ¬μ©νκ³ μΆμ΅λλ€. Hibernateμμ μ§μ μ§μνμ§ μλλ€κ³ μκ°ν©λλ€. μ΄κ²μ΄ λ΄κ° https://vladmihalcea.com/how-to-map-json-objects-using-generic-hibernate-types/ μ μμ‘΄ν μ΄μ μ
λλ€. λλ μλ₯Ό λ€μ΄ https://thorben-janssen.com/persist-postgresqls-jsonb-data-type-hibernate/ μ¬κΈ°μμ κ°μ΄λλ UserType μ μ¬μ©ν©λλ€.
λ§μ΅λλ€. νμ§λ§ Java String
λ₯Ό JSONB
μ νμ μ΄μ 맀ννλ κ²κ³Ό κ°μ΄ μ λ§ κ°λ¨ν μμ
μ μλν΄ λ³΄μ
¨μ΅λκΉ? ν¨κ³Όκ° μλ€λ©΄ μΆ©λΆν μ’κ² μ£ ?
@gavinking μλμ μμ§ μλνμ§ μμμ΅λλ€. μ, μΆ©λΆν μ’μ κ²μ λλ€. λ΄ μν°ν°λ₯Ό DBμ μ½μ νκΈ° μ μ JSON κ°μ²΄λ₯Ό JSON λ¬Έμμ΄λ‘ λ³ννκΈ°λ§ νλ©΄ λ©λλ€.
κ·Έλ λ€λ©΄ Vert.x ν΄λΌμ΄μΈνΈκ° μ΄λ―Έ ν΄λΉ μ ν λ³νμ μ§μνλ κ²μΌ μ μμ΅λλ€. μ°λ¦¬λ μλν΄μΌ νμ§λ§ μ§μνμ§ μλλΌλ μλ§λ κ·ΈλμΌ νλ€κ³ μκ°ν©λλ€.
@DavidD μ¬κΈ° μνκ° μ΄λ»μ΅λκΉ? μ΄ λΆλΆμ μμΈν μ΄ν΄λ³ΌκΉμ?
λλ κΈΈμ μμλ€. μκ°μ΄ μμΌλ©΄ μ΄ λ¬Έμ λ₯Ό ν΄κ²°νμμμ€.
#301μμ UserType
κ° HRμμ μλνλ€λ κ²μ 보μ¬μ£Όλ ν
μ€νΈλ₯Ό μΆκ°νμ΅λλ€. μ΅μν PreparedStatement
λ° ResultSet
μ΄λν°κ° JDBC( νΉν ν° λ²μλ μλλλ€).
@gavinking pg-client μ νμ λν΄ μΌμ’ μ 맀νμ μ§μν΄μΌ ν©λκΉ?
JSON (io.reactiverse.pgclient.data.Json) JSONB (io.reactiverse.pgclient.data.Json) POINT (io.reactiverse.pgclient.data.Point) LINE (io.reactiverse.pgclient.data.Line) LSEG (io.reactiverse.pgclient.data.LineSegment) BOX (io.reactiverse.pgclient.data.Box) PATH (io.reactiverse.pgclient.data.Path) POLYGON (io.reactiverse.pgclient.data.Polygon) CIRCLE (io.reactiverse.pgclient.data.Circle)
μ΄μ μ§λ¬Έμ λ€μκ³Ό κ°μ΅λλ€. PostgreSQL ν΄λΌμ΄μΈνΈμ λν κ°λ ₯ν μ’
μμ±μ μμ±νμ§ μκ³ JDBC μ΄λν°μμ getObject()
λ° setObject()
κ° μ΄λ¬ν μ νμ μ§μνλλ‘ ν μ μμ΅λκΉ?
λ€μκ³Ό κ°μ κ²μ΄ κ°λ₯ν©λκΉ?
@Type(type="passthrough")
Circle circle
λ³νμ μννμ§ μκ³ κ°μ μλ κ·Έλλ‘ μ λ¬ν©λκΉ?
μ΄μ μ§λ¬Έμ λ€μκ³Ό κ°μ΅λλ€. PostgreSQL ν΄λΌμ΄μΈνΈμ λν κ°λ ₯ν μ’ μμ±μ μμ±νμ§ μκ³ JDBC μ΄λν°μμ
getObject()
λ°setObject()
λ₯Ό λ§λ€ μ μμ΅λκΉ?
κΈμ, λλ μ΄κ²μ μλνκ³ λΆλͺ
ν Postgres λλ MySQLμμ io.vertx.core.json.JsonObject
λ₯Ό μ²λ¦¬νκΈ° μν΄ μ€μ λ‘ νΉλ³ν μμ
μ μνν νμκ° μμ΅λλ€. λΉμ μ μ¬μ©ν μ μμ΅λλ€ getObject()
/ setObject()
λΉμ μμ UserType
.
μ΄κ²μ μλν©λλ€:
public class Json implements UserType {
<strong i="15">@Override</strong>
public int[] sqlTypes() {
return new int[] {Types.OTHER};
}
<strong i="16">@Override</strong>
public Class returnedClass() {
return JsonObject.class;
}
<strong i="17">@Override</strong>
public boolean equals(Object x, Object y) throws HibernateException {
return Objects.equals(x,y);
}
<strong i="18">@Override</strong>
public int hashCode(Object x) throws HibernateException {
return Objects.hashCode(x);
}
<strong i="19">@Override</strong>
public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) throws HibernateException, SQLException {
return rs.getObject(names[0]);
}
<strong i="20">@Override</strong>
public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session) throws HibernateException, SQLException {
if (value==null) {
st.setNull(index, Types.OTHER);
}
else {
st.setObject(index, value);
}
}
...
}
λ€μκ³Ό κ°μ κ²μ΄ κ°λ₯ν©λκΉ?
@Type(type="passthrough") Circle circle
λ³νμ μννμ§ μκ³ κ°μ μλ κ·Έλλ‘ μ λ¬ν©λκΉ?
μ, κ·Έκ²λ μλν©λλ€.
54434c94b3ff57261fd905abaeb25961b2ed285cλ₯Ό μ°Έμ‘°νμμμ€.
μ΄ λ¬Έμ λ₯Ό μ’ λ£ν μ μμ΅λλ€.
μλ₯Ό λ€μ΄ io.reactiverse.pgclient.data.Circle
μ κ°μ λ€λ₯Έ μ νμ μ΄λ»μ΅λκΉ?
@akoufaλ μ΄μ μλ μ§λ¬Έμ λν ꡬ체μ μΈ λ΅λ³μ μ 곡ν©λλ€.
Hibernate Reactiveλ μ¬μ©μ μ μ
UserTypes
ν©λκΉ?
λλ΅μ μμ λλ€!
κ·Έλ¬λ μ°λ¦¬κ° UserType
JDBC μ λ§€μ° μ μ¬ν κ²μ λ
ΈμΆνλλΌλ μλ°ν JDBC μ°κ²°μ΄ μκ³ μμ ν λ€λ₯Έ λΉμ°¨λ¨ λ°μ΄ν°λ² μ΄μ€ ν΄λΌμ΄μΈνΈκ° μμμ μμμΌ ν©λλ€. κ·Έλμ μ΄λ€ κ²λ€μ λ¨μν μλνμ§ μμ κ²μ
λλ€.
λλ λ€μ λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©νκ³ μμλ€ https://github.com/vladmihalcea/hibernate-types
κ·Έλμ λλ λΉμ μ΄ κ·Έκ²μ λν΄ κ½€ νμ€μ μΌ νμκ° μλ€κ³ μκ°ν©λλ€. μμ λΌμ΄λΈλ¬λ¦¬λ JDBCμ ν¨κ» μλνλλ‘ μμ±λμμΌλ―λ‘ UserType
μ€ μΌλΆ λ μλν μ μμ§λ§
λμμΌλ‘ Hibernateμ
UserType
μ λν JSONB Postgres μ§μμ λΉλνλ μ΄ κΈ°μ¬λ₯Ό μ°Ύμμ΅λλ€.
ν
μ€νΈ μ€μνΈμμ μ΄κ²μ μ΄λ»κ² ꡬννλμ§ μ΄ν΄λ³΄μμμ€. κΈ°λ³Έμ μΈ μμ΄λμ΄λ λΉμ μ΄ Vert.x ν΅κ³Όν΄μΌνλ€λ κ²μ
λλ€ JsonObject
λ°λ‘ νΈμΆνμ¬ Vert.xμ PostgreSQL λλ MySQLμ ν΄λΌμ΄μΈνΈμ setObject()
.
μλ₯Ό λ€μ΄
io.reactiverse.pgclient.data.Circle
μ κ°μ λ€λ₯Έ μ νμ μ΄λ»μ΅λκΉ?
ν μ€νΈνμ§ μμμ§λ§ λμΌν κ±°λμ¬μΌ ν©λλ€.
κ·Έλ°λ° io.reactiverse.pgclient.data
μ΄(κ°) μ£½μμ΅λλ€. μ΄μ λ²μ μ ν΄λΌμ΄μΈνΈμ©μ
λλ€. κ·Έκ²μ λΉμ μ΄λ³΄κ³ ν΄μΌ ν κ²μ΄ μλλλ€.
νμ¬ μ ν λͺ©λ‘μ λ€μκ³Ό κ°μ΅λλ€.
https://vertx.io/docs/vertx-pg-client/java/#_postgresql_type_mapping
μ΄ν΄νμ§λ§ Java Stringμ JSONB μ νμ μ΄μ 맀ννλ κ²κ³Ό κ°μ΄ μ λ§ κ°λ¨ν μμ μ μλν μ μ΄ μμ΅λκΉ?
...
κ·Έλ λ€λ©΄ Vert.x ν΄λΌμ΄μΈνΈκ° μ΄λ―Έ ν΄λΉ μ ν λ³νμ μ§μνλ κ²μΌ μ μμ΅λλ€. μ°λ¦¬λ μλν΄μΌ νμ§λ§ μ§μνμ§ μλλΌλ μλ§λ κ·ΈλμΌ νλ€κ³ μκ°ν©λλ€.
μμ λ§ν¬ λ λ¬Έμμ λ°λ₯΄λ©΄ μ΄κ²μ΄ μλ ν©λλ€. JSONB
-types μ΄μ μ§μ μ μλ₯Ό μ°λ κ²λ ν
μ€νΈνλλ° μλνμ΅λλ€.
λ°λΌμ μμΉμ μΌλ‘ μνμ§ μλ κ²½μ° JsonObject
λ‘ μλ§μ΄ λ νμμ‘°μ°¨ μμ΅λλ€. (μλ§λ λ κΉ¨λν κ²μ
λλ€.)
λ¬Όλ‘ μ λλ€. λ€λ₯Έ νΉμ μ νμ λν ν μ€νΈλ₯Ό μΆκ°ν μ μμ΅λκΉ? μ μ΄λ μμ²λΌ. 맀νμ΄ μ΄λ»κ² μκ²Όλμ§ λ³΄μ¬μ€ μ μλλ‘
μλ νμΈμ!
μ¬λ¬λΆμ hibernate-reactiveμ ν¨κ» μ¬μ©ν https://github.com/vladmihalcea/hibernate-types μ κ°μ λΌμ΄λΈλ¬λ¦¬λ₯Ό λ³Έ μ μ΄ μμ΅λκΉ?
μμ§ μ‘΄μ¬νμ§ μλλ€λ©΄ λ΄ νλ‘μ νΈλ₯Ό μν΄ λ¬΄μΈκ°λ₯Ό λ§λ€κ³ μΆμ΅λλ€(quarkus μ¬μ©). Postgresμμ λ§μ JSON μ΄μ μ¬μ©ν©λλ€.
νμ§λ§ λ΄κ° μλͺ» μ΄ν΄νλμ§ λͺ¨λ₯΄κ² μ§λ§ hibernate-reactive
λ UserType
μΈν°νμ΄μ€μμ ꡬννμ¬ μ¬μ©μ μ μ μ νλ§ νμ©ν©λκΉ? (http://hibernate.org/reactive/documentation/1.0/reference/html_single/#_custom_types)
@AlexandreGuidin , λλ @gavinkingμ΄ μ΄λ―Έ μ΄μ λκΈ μ€ νλμμ κ·νμ μ§λ¬Έμ λ΅λ³νλ€κ³ μκ°ν©λλ€: https://github.com/hibernate/hibernate-reactive/issues/279#issuecomment -666289449
νμ§λ§ μ κ° λμΉκ³ μλ λΆλΆμ΄ μλ€λ©΄ λͺ κ°μ§ μΆκ° μ§λ¬Έμ λ¨κ²¨μ£ΌμΈμ.