使用hibernate在Mysql 5.7数据库中存储/检索Json数据

Posted

技术标签:

【中文标题】使用hibernate在Mysql 5.7数据库中存储/检索Json数据【英文标题】:Store/Retrieve Json data to/from Mysql 5.7 database using hibernate 【发布时间】:2015-12-25 11:43:01 【问题描述】:

我将开始一个需要生成动态谷歌表单的项目。这个项目的要求是我需要使用 mysql 5.7,以便我可以使用 json 数据类型来存储/检索 json 数据。我对此很好。我知道,可以使用 HQL。但我想不通的是如何使用 Hibernate 使用对象关系映射来实现它?

有什么想法吗?

提前致谢!

【问题讨论】:

我想这是可能的,但是我不认为有一个简单的方法,当然这是很多工作......你知道torodb吗?他们正在做同样的事情,但我猜他们不使用HQL,而在他们下面有postgresql...祝你好运。 【参考方案1】:

最近我解决了类似的任务。我想为时已晚,但也许有人觉得这很有用。

简短回答:您应该创建必须实现 org.hibernate.usertype.UserType的类(如“com.test.MyJsonType”) > nullSafeGet 方法应该将 JSON 反序列化为 java 对象(使用 Jackson)的接口,nullSafeSet 将 POJO 序列化为 JSON 和一些其他辅助方法。

那么你应该扩展 MySQLDialect 并注册新的列类型“json”。

最后,您可以通过 @Type(type = "com.test.MyJsonType") 注释实体字段,这些字段应该映射到 MySQL json 列。

如果你不想用包名写类型,你也可以阅读@TypeDef here。

例如:

public class MyJsonType implements UserType 

@Override
public int[] sqlTypes() 
    return new int[]  Types.VARCHAR ;


@Override
public Class<Characteristics> returnedClass() 
    return Characteristics.class;


@Override
public Object nullSafeGet(final ResultSet rs, final String[] names, final SessionImplementor session, final Object owner)
        throws HibernateException, SQLException 
    final String cellContent = rs.getString(names[0]);
    if (cellContent == null) 
        return null;
    
    try 
        final ObjectMapper mapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        return mapper.readValue(cellContent.getBytes("UTF-8"), returnedClass());
     catch (final Exception ex) 
        throw new RuntimeException("Failed to convert String to Invoice: " + ex.getMessage(), ex);
    


@Override
public void nullSafeSet(final PreparedStatement ps, final Object value, final int idx, final SessionImplementor session)
        throws HibernateException, SQLException 
    if (value == null) 
        ps.setNull(idx, Types.VARCHAR);
        return;
    
    try 
        final ObjectMapper mapper = new ObjectMapper();
        final StringWriter w = new StringWriter();
        mapper.writeValue(w, value);
        w.flush();
        ps.setObject(idx, w.toString(), Types.VARCHAR);
     catch (final Exception ex) 
        throw new RuntimeException("Failed to convert Invoice to String: " + ex.getMessage(), ex);
    


@Override
public Object deepCopy(final Object value) throws HibernateException 
    try 
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(value);
        oos.flush();
        oos.close();
        bos.close();

        ByteArrayInputStream bais = new ByteArrayInputStream(bos.toByteArray());
        return new ObjectInputStream(bais).readObject();
     catch (ClassNotFoundException | IOException ex) 
        throw new HibernateException(ex);
    


@Override
public boolean isMutable() 
    return true;


@Override
public Serializable disassemble(final Object value) throws HibernateException 
    return (Serializable) this.deepCopy(value);


@Override
public Object assemble(final Serializable cached, final Object owner) throws HibernateException 
    return this.deepCopy(cached);


@Override
public Object replace(final Object original, final Object target, final Object owner) throws HibernateException 
    return this.deepCopy(original);


@Override
public boolean equals(Object x, Object y) throws HibernateException 
    return Objects.equals(x, y);


@Override
public int hashCode(Object x) throws HibernateException 
    return Objects.hashCode(x);



POJO 类:

public class Characteristics implements Serializable 

private String field;

public String getField() 
    return field;


public void setField(String field) 
    this.field= field;


@Override
public boolean equals(Object obj) 

    if (obj == null) return false;
    if (getClass() != obj.getClass()) return false;
    final Characteristics other = (Characteristics) obj;
    return Objects.equals(this.field, other.field);



@Override
public int hashCode() 

    return Objects.hash(this.field);



注册新的列类型:

public class JsonMySQLDialect extends MySQLDialect 

public JsonMySQLDialect() 
    this.registerColumnType(Types.VARCHAR, "json");



使用:

@Entity
@Table(name = "Table")
public class TableClass 
...
@Column
@Type(type = "com.test.MyJsonType")
protected Characteristics characteristics;
...

【讨论】:

是创建“json”还是varchar类型的列? 它创建“json”列类型。 Java 自动调用 super()。但如果你愿意,你可以显式调用它。 嗨,你能给我一个涉及数组的例子吗,比如特征是一个数组。 @user5500750 我认为你可以在TableClass 中执行以下操作:protected Characteristics[] characteristics; 虽然我还没有测试过,所以不要引用我的话。

以上是关于使用hibernate在Mysql 5.7数据库中存储/检索Json数据的主要内容,如果未能解决你的问题,请参考以下文章

MySql 5.7关键字和保留字-附表

MySQL 从 5.6 升级到 5.7 的 Grails 更改

Mysql 5.7 json 数据类型,在 Rails 5 中使用 activerecord 查询

性能问题 MySQL 5.7

如何在MySQL 5.7中使用SELECT ... INTO语句导出数据文件?

如何将 MySQL 5.5.40 升级到 MySQL 5.7