hibernate跨数据库,json字段处理方案,自定义扩展JsonStringType(hibernate json)

  本篇文章为你整理了hibernate跨数据库,json字段处理方案,自定义扩展JsonStringType(hibernate json)的详细内容,包含有json数据库互转 hibernate json json跨平台 json文件代替数据库 hibernate跨数据库,json字段处理方案,自定义扩展JsonStringType,希望能帮助你了解 hibernate跨数据库,json字段处理方案,自定义扩展JsonStringType。

  对于一些不经常更新的静态数据,我们喜欢使用json格式存储。推荐的做法是将json数据存储在key-value数据库,但这无疑增加了技术成本,所以我们通常还是存储在RDB数据库中。我们在使用hibernate,对json数据的存取期望是,存能自动转换为json格式存储,取能自动将json数据转换为对象数据。在数据库方面,Mysql5.7版本以后新增的功能,Mysql提供了一个原生的Json类型,Json值将不再以字符串的形式存储,而是采用一种允许快速读取文本元素(document elements)的内部二进制(internal binary)格式。在Json列插入或者更新的时候将会自动验证Json文本,未通过验证的文本将产生一个错误信息。而除了mysql,pg极少部分支持json字段类型的其他数据库,还是需要大文本字段进行存储。

  二、实现方案

  关键技术: hibernate-types 将Java对象或Jackson JsonNode为JPA实体属性。

  引入依赖-hibernate-types

  

 dependency 

 

   groupId com.vladmihalcea /groupId

   artifactId hibernate-types-52 /artifactId

   version 2.10.1 /version

   /dependency

  

 

  定义实体类

  

import com.alibaba.fastjson.JSONObject;

 

  import com.vladmihalcea.hibernate.type.array.IntArrayType;

  import com.vladmihalcea.hibernate.type.array.StringArrayType;

  import com.vladmihalcea.hibernate.type.json.JsonBinaryType;

  import com.vladmihalcea.hibernate.type.json.JsonStringType;

  import lombok.Data;

  import org.hibernate.annotations.Type;

  import org.hibernate.annotations.TypeDef;

  import org.hibernate.annotations.TypeDefs;

  import javax.persistence.*;

  @Data

  @Entity

  @Table(name = "parents")

  @TypeDefs({

   @TypeDef(name = "string-array", typeClass = StringArrayType.class),

   @TypeDef(name = "json", typeClass = JsonStringType.class),

   @TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)

  public class TestEntity implements Serializable {

   private Long id;

   @Column(name = "attr")

   @Type(type = "jsonb")

   private JSONObject attr;

   @Column(name = "user_list")

   @Type(type = "json")

   private List User userList;

   @Column(name = "ava_img")

   @Type(type = "string-array")

   private String[] avaImg;

  

 

  以上为常规操作,在多数据库使用时,你会发现,JsonStringType 类型会转为数据库默认的 varchar(255),根本就存储不了长一点的json数据。

  三、扩展JsonStringType,适配多数据库json字段存储

  也许网络上一搜JsonStringType适配性问题,答案基本都是建议用 @Column(columnDefinition = "json") 、 @Column(columnDefinition = "varchar(max)") 这种写法,我在上一篇文章中说了,columnDefinition具有不可移植性,只能适配一种或一类数据库。所以,需要自定义扩展JsonStringType。

  先分析JsonStringType源码
 

  
 

  可以看到JsonStringType的类型描述时由JsonStringSqlTypeDescriptor提供的
 

  
 

  而JsonStringSqlTypeDescriptor中,将数据库对应的类型写死为 12
 

  12对应数据库字段类型是varchar,这也太坑了,直接给JsonStringType对应的数据库字段类型写死。

  JsonStringType兼容办法
 

  既然我们找到了问题原因,那么我们就容易解决,解决主要思路是将JsonStringType类型对应的数据库字段类型可配置
 

  接着看源码
 

  
 

  JsonStringSqlTypeDescriptor 的父类是 AbstractJsonSqlTypeDescriptor
 

  
 

  在AbstractJsonSqlTypeDescriptor中,将json格式写死为1111,也就是 Types.OTHER类型
 

  我们重新定义一个JsonStringType,不将SqlType写死,然后通过配置database-platform指定hibernate方言中,将1111转换为我们需要的格式。
 

  源码如下:

  
import com.fasterxml.jackson.databind.ObjectMapper;

  import com.vladmihalcea.hibernate.type.AbstractHibernateType;

  import com.vladmihalcea.hibernate.type.json.internal.JsonTypeDescriptor;

  import com.vladmihalcea.hibernate.type.util.Configuration;

  import com.vladmihalcea.hibernate.type.util.ObjectMapperWrapper;

  import org.hibernate.usertype.DynamicParameterizedType;

  import java.lang.reflect.Type;

  import java.util.Properties;

  public class MyJsonStringType extends AbstractHibernateType Object implements DynamicParameterizedType {

   public static final MyJsonStringType INSTANCE = new MyJsonStringType();

   public MyJsonStringType() {

   super(MyJsonStringSqlTypeDescriptor.INSTANCE, new JsonTypeDescriptor(Configuration.INSTANCE.getObjectMapperWrapper()));

   public MyJsonStringType(Type javaType) {

   super(MyJsonStringSqlTypeDescriptor.INSTANCE, new JsonTypeDescriptor(Configuration.INSTANCE.getObjectMapperWrapper(), javaType));

   public MyJsonStringType(Configuration configuration) {

   super(MyJsonStringSqlTypeDescriptor.INSTANCE, new JsonTypeDescriptor(configuration.getObjectMapperWrapper()), configuration);

   public MyJsonStringType(ObjectMapper objectMapper) {

   super(MyJsonStringSqlTypeDescriptor.INSTANCE, new JsonTypeDescriptor(new ObjectMapperWrapper(objectMapper)));

   public MyJsonStringType(ObjectMapperWrapper objectMapperWrapper) {

   super(MyJsonStringSqlTypeDescriptor.INSTANCE, new JsonTypeDescriptor(objectMapperWrapper));

   public MyJsonStringType(ObjectMapper objectMapper, Type javaType) {

   super(MyJsonStringSqlTypeDescriptor.INSTANCE, new JsonTypeDescriptor(new ObjectMapperWrapper(objectMapper), javaType));

   public MyJsonStringType(ObjectMapperWrapper objectMapperWrapper, Type javaType) {

   super(MyJsonStringSqlTypeDescriptor.INSTANCE, new JsonTypeDescriptor(objectMapperWrapper, javaType));

   public String getName() {

   return "json";

   protected boolean registerUnderJavaType() {

   return true;

   public void setParameterValues(Properties parameters) {

   ((JsonTypeDescriptor) this.getJavaTypeDescriptor()).setParameterValues(parameters);

  
MyJsonStringSqlTypeDescriptor(点击展开)

  

import com.vladmihalcea.hibernate.type.json.internal.AbstractJsonSqlTypeDescriptor;

 

  import org.hibernate.type.descriptor.ValueBinder;

  import org.hibernate.type.descriptor.WrapperOptions;

  import org.hibernate.type.descriptor.java.JavaTypeDescriptor;

  import org.hibernate.type.descriptor.sql.BasicBinder;

  import java.sql.CallableStatement;

  import java.sql.PreparedStatement;

  import java.sql.ResultSet;

  import java.sql.SQLException;

  public class MyJsonStringSqlTypeDescriptor extends AbstractJsonSqlTypeDescriptor {

   public static final MyJsonStringSqlTypeDescriptor INSTANCE = new MyJsonStringSqlTypeDescriptor();

   public MyJsonStringSqlTypeDescriptor() {

   public X ValueBinder X getBinder(final JavaTypeDescriptor X javaTypeDescriptor) {

   return new BasicBinder X (javaTypeDescriptor, this) {

   protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) throws SQLException {

   st.setString(index, (String)javaTypeDescriptor.unwrap(value, String.class, options));

   protected void doBind(CallableStatement st, X value, String name, WrapperOptions options) throws SQLException {

   st.setString(name, (String)javaTypeDescriptor.unwrap(value, String.class, options));

   protected Object extractJson(ResultSet rs, String name) throws SQLException {

   return rs.getString(name);

   protected Object extractJson(CallableStatement statement, int index) throws SQLException {

   return statement.getString(index);

   protected Object extractJson(CallableStatement statement, String name) throws SQLException {

   return statement.getString(name);

  

 

  实体json定义改为
 

  @TypeDef(name="json",typeClass = MyJsonStringType.class)
 

  大功告成,下边就可以根据不同数据库自适应数据库json字段类型

  以上就是hibernate跨数据库,json字段处理方案,自定义扩展JsonStringType(hibernate json)的详细内容,想要了解更多 hibernate跨数据库,json字段处理方案,自定义扩展JsonStringType的内容,请持续关注盛行IT软件开发工作室。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

留言与评论(共有 条评论)
   
验证码: