最近的項目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