Hibernate 映射數據庫中Json字段的解決方案

最近的項目ORM框架使用的是Hibernate,數據庫使用PostgreSQL,倆個都是開源的高大上產品,Hibernate就不用說啦,主流的ORM框架,PostgreSQL第一次接觸,其中包含Json數據類型的字段,這種類型意味着它能夠像非關係型數據庫那樣存儲數據,數據擴展性很是好,這也是項目使用它的主要緣由之一。 在Hibernate和PostgreSQL的結合過程當中遇到了針對Json數據類型,Hibernate並無Json這種數據映射字段,想了下是否是版本的問題,也許高版本Hibernate已經支持這種類型啦,下載最新版本Hibernate看下啦,仍然不支持,這點不是很明白,PostgreSQL已經支持Json這麼長時間啦,並且如今MySQL最新版本也已經支持Json數據格式啦,身爲主流ORM框架怎麼到如今尚未提供這種數據類型,無論啦,也許人家提供了其餘想法,大公司的想法是咱們這些吊私沒法猜想的,做爲咱們就是尋找解決方案就能夠啦,畢竟人家已經開源了嘛。
畢竟這倆框架已經誕生這麼長時間啦,這種常見問題確定有了很好的解決方案,果真在stackoverflow找到了一些解決方案,這裏只作整理說明,可以解決當前項目中的問題,不作深刻探究。前端

如今有倆種方案:

一、在數據庫端處理java

CREATE OR REPLACE FUNCTION json_intext(text) RETURNS json AS $$ SELECT json_in($1::cstring); 
$$ LANGUAGE SQL IMMUTABLE;

上面的函數是將指定text類型數據轉換成json數據個數sql

二、在Hibernate端處理數據庫

import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.usertype.UserType;

import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;

/** * @author timfulmer */
public class StringJsonUserType implements UserType {

    /** * Return the SQL type codes for the columns mapped by this type. The * codes are defined on <tt>java.sql.Types</tt>. * * @return int[] the typecodes * @see java.sql.Types */
    @Override
    public int[] sqlTypes() {
        return new int[] { Types.JAVA_OBJECT};
    }

    /** * The class returned by <tt>nullSafeGet()</tt>. * * @return Class */
    @Override
    public Class returnedClass() {
        return String.class;
    }

    /** * Compare two instances of the class mapped by this type for persistence "equality". * Equality of the persistent state. * * @param x * @param y * @return boolean */
    @Override
    public boolean equals(Object x, Object y) throws HibernateException {

        if( x== null){

            return y== null;
        }

        return x.equals( y);
    }

    /** * Get a hashcode for the instance, consistent with persistence "equality" */
    @Override
    public int hashCode(Object x) throws HibernateException {

        return x.hashCode();
    }

    /** * Retrieve an instance of the mapped class from a JDBC resultset. Implementors * should handle possibility of null values. * * @param rs a JDBC result set * @param names the column names * @param session * @param owner the containing entity  @return Object * @throws org.hibernate.HibernateException * * @throws java.sql.SQLException */
    @Override
    public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException {
        if(rs.getString(names[0]) == null){
            return null;
        }
        return rs.getString(names[0]);
    }

    /** * Write an instance of the mapped class to a prepared statement. Implementors * should handle possibility of null values. A multi-column type should be written * to parameters starting from <tt>index</tt>. * * @param st a JDBC prepared statement * @param value the object to write * @param index statement parameter index * @param session * @throws org.hibernate.HibernateException * * @throws java.sql.SQLException */
    @Override
    public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws HibernateException, SQLException {
        if (value == null) {
            st.setNull(index, Types.OTHER);
            return;
        }

        st.setObject(index, value, Types.OTHER);
    }

    /** * Return a deep copy of the persistent state, stopping at entities and at * collections. It is not necessary to copy immutable objects, or null * values, in which case it is safe to simply return the argument. * * @param value the object to be cloned, which may be null * @return Object a copy */
    @Override
    public Object deepCopy(Object value) throws HibernateException {

        return value;
    }

    /** * Are objects of this type mutable? * * @return boolean */
    @Override
    public boolean isMutable() {
        return true;
    }

    /** * Transform the object into its cacheable representation. At the very least this * method should perform a deep copy if the type is mutable. That may not be enough * for some implementations, however; for example, associations must be cached as * identifier values. (optional operation) * * @param value the object to be cached * @return a cachable representation of the object * @throws org.hibernate.HibernateException * */
    @Override
    public Serializable disassemble(Object value) throws HibernateException {
        return (String)this.deepCopy( value);
    }

    /** * Reconstruct an object from the cacheable representation. At the very least this * method should perform a deep copy if the type is mutable. (optional operation) * * @param cached the object to be cached * @param owner the owner of the cached object * @return a reconstructed object from the cachable representation * @throws org.hibernate.HibernateException * */
    @Override
    public Object assemble(Serializable cached, Object owner) throws HibernateException {
        return this.deepCopy( cached);
    }

    /** * During merge, replace the existing (target) value in the entity we are merging to * with a new (original) value from the detached entity we are merging. For immutable * objects, or null values, it is safe to simply return the first parameter. For * mutable objects, it is safe to return a copy of the first parameter. For objects * with component values, it might make sense to recursively replace component values. * * @param original the value from the detached entity being merged * @param target the value in the managed entity * @return the value to be merged */
    @Override
    public Object replace(Object original, Object target, Object owner) throws HibernateException {
        return original;
    }
}

上面的類實現Hibernate的UserType接口,這樣就能夠定義Hibernate端的數據類型,這樣將對應數據庫中Json字段的JavaBean中的數據字段定義成String類型,這樣javaBean中指定字段就能和數據庫中json造成映射json

例如sass

<property name="atts" type="com.quangao.hibernate.StringJsonUserType">
     <column name="atts"  />
</property>

這樣session.save(entity);的時候就能夠將json字段成功保存markdown

上述倆種方法,第一種雖能實現,但需在數據中頻繁轉換,自己簡單的保存修改變得很麻煩,明顯不切符合解耦概念,這是將前端的事情強加給數據庫來處理的,並且不符合Hibernate存在的緣由,二第二種方法很好的實現了所謂的映射關係,數據庫端不須要作任何多餘的事情。因此我選擇了第二種方案。session

版權聲明:本文爲博主原創文章,未經博主容許不得轉載。app

相關文章
相關標籤/搜索