Hibernate存取JSON数据

一、场景

public class OrderModel {

private List<String> favorableDescList;

}

 

订单中会存储一些优惠信息,方便页面展示时使用,如:

1、满100减50

2、参与【老会员真情回馈——精品课程体验活动】,仅需支付200.00学币

3、【Oracle + PL/SQL 实战】套装课程的【抢购】活动,优惠120.00学币

……等等

 

如图所示,我们在页面给用户展示他们参与的优惠信息:


二、分析

如上优惠信息有如下特点:

1、只用于展示,不会涉及修改;

2、一旦订单支付成功,不会再改变;

3、数据量不会很大。

三、解决方案

1、最简单的解决方案是关联表:


 但这种解决方案需要连表进行查询,感觉是没有必要的,毕竟只是展示数据,用关联表有点杀鸡用牛刀的感觉。

 

 

2、JSON解决方案:

 

通过如上思路我们可以解决许多类似的问题。

 

 

3、代码示例:

 

1、模型类:

Java代码   收藏代码
  1. public class OrderModel {  
  2.     @Type(type = "cn.javass.framework.hibernate.type.JsonType")  //①  
  3.     private List<String> favorableDescList;  
  4. }  

 ①处使用我们自定义的Hibernate类型来进行转换,上边代码只有一部分

 

2、自定义JsonType

Java代码   收藏代码
  1. package cn.javass.framework.hibernate.type;  
  2. //省略import  
  3. public class JsonType implements UserType, Serializable {  
  4.     private String json;  
  5.     @Override  
  6.     public int[] sqlTypes() {  
  7.         return new int[] {Hibernate.STRING.sqlType()};  
  8.     }  
  9.     @Override  
  10.     public Class returnedClass() {  
  11.         return JsonList.class;  
  12.     }  
  13.     @Override  
  14.     public boolean equals(Object o, Object o1) throws HibernateException {  
  15.         if (o == o1) {  
  16.             return true;  
  17.         }  
  18.         if (o == null || o == null) {  
  19.             return false;  
  20.         }  
  21.   
  22.         return o.equals(o1);  
  23.     }  
  24.   
  25.     @Override  
  26.     public int hashCode(Object o) throws HibernateException {  
  27.         return o.hashCode();  
  28.     }  
  29.   
  30.   
  31.     /** 
  32.   * 从JDBC ResultSet读取数据,将其转换为自定义类型后返回 
  33.   * (此方法要求对克能出现null值进行处理) 
  34.   * names中包含了当前自定义类型的映射字段名称 
  35.   * @param resultSet 
  36.   * @param names 
  37.   * @param owner 
  38.   * @return 
  39.   * @throws HibernateException 
  40.   * @throws SQLException 
  41.   */  
  42.     @Override  
  43.     public Object nullSafeGet(ResultSet resultSet, String[] names, Object owner) throws HibernateException, SQLException {  
  44.         String json = resultSet.getString(names[0]);  
  45.         if(json == null || json.trim().length() == 0) {  
  46.             return new JsonList();  
  47.         }  
  48.         return JSONArray.toList(JSONArray.fromObject(json), JsonList.class);  
  49.     }  
  50.   
  51.      /** 
  52.   * 本方法将在Hibernate进行数据保存时被调用 
  53.   * 我们可以通过PreparedStateme将自定义数据写入到对应的数据库表字段 
  54.   * @param preparedStatement 
  55.   * @param value 
  56.   * @param i 
  57.   * @throws HibernateException 
  58.   * @throws SQLException 
  59.   */  
  60.     @Override  
  61.     public void nullSafeSet(PreparedStatement preparedStatement, Object value, int i) throws HibernateException, SQLException {  
  62.         if(value == null) {  
  63.             preparedStatement.setNull(i, Hibernate.STRING.sqlType());  
  64.         } else {  
  65.             preparedStatement.setString(i, JSONArray.fromObject(value).toString());  
  66.         }  
  67.     }  
  68.   
  69.     /** 
  70.      * 提供自定义类型的完全复制方法 
  71.      * 本方法将用构造返回对象 
  72.      * 当nullSafeGet方法调用之后,我们获得了自定义数据对象,在向用户返回自定义数据之前, 
  73.      * deepCopy方法将被调用,它将根据自定义数据对象构造一个完全拷贝,并将此拷贝返回给用户 
  74.      * 此时我们就得到了自定义数据对象的两个版本,第一个是从数据库读出的原始版本,其二是我们通过 
  75.      * deepCopy方法构造的复制版本,原始的版本将有Hibernate维护,复制版由用户使用。原始版本用作 
  76.      * 稍后的脏数据检查依据;Hibernate将在脏数据检查过程中将两个版本的数据进行对比(通过调用 
  77.      * equals方法),如果数据发生了变化(equals方法返回false),则执行对应的持久化操作 
  78.      * 
  79.      * @param o 
  80.      * @return 
  81.      * @throws HibernateException 
  82.      */  
  83.     @Override  
  84.     public Object deepCopy(Object o) throws HibernateException {  
  85.         if(o == nullreturn null;  
  86.         JsonList jsonList = new JsonList();  
  87.         jsonList.addAll((List)o);  
  88.         return jsonList;  
  89.     }  
  90.   
  91.     /** 
  92.      * 本类型实例是否可变 
  93.      * @return 
  94.     */  
  95.     @Override  
  96.     public boolean isMutable() {  
  97.         return true;  
  98.     }  
  99.   
  100.     /* 序列化 */  
  101.     @Override  
  102.     public Serializable disassemble(Object value) throws HibernateException {  
  103.         return ((Serializable)value);  
  104.     }  
  105.   
  106.     /* 反序列化 */  
  107.     @Override  
  108.     public Object assemble(Serializable cached, Object owner) throws HibernateException {  
  109.         return cached;  
  110.     }  
  111.   
  112.     @Override  
  113.     public Object replace(Object original, Object target, Object owner) throws HibernateException {  
  114.         return original;  
  115.     }  
  116. }  

 JSON框架使用的是json-lib 2.1。

 

3、自定义JsonList

Java代码   收藏代码
  1. package cn.javass.framework.hibernate;  
  2. public class JsonList<T> extends ArrayList implements Cloneable {  
  3. }  

 

就这么简单,欢迎大家讨论。

 

订单Model属于公司机密,不方便附上,其他两个类请附件下载(JsonType和JsonList的源代码)。

 

 

 

 

 

有人说有性能问题,我写了个测试用例:

 

测试机器:CPU:p8700(双核@2.53GHZ)  内存:2G

 

一、插入

1、JSON方式插入10w条

create 100000 elapsed time(millis):21031

2、关联表插入10w条

create 100000 elapsed time(millis):79219

 

JSON性能远远好于关联表,关联表要插入两个表。

 

 

二、查询

1、JSON方式分页(100条一页)查询10w条

select 100000 elapsed time(millis):146047

2、关联表分页(100条一页)查询10w条

select 100000 elapsed time(millis):275375

 

JSON性能远远好于关联表,关联表需要join连表查询。

 

JSON方式的缺点:分析统计等查询是鸡肋、大数据量是鸡肋(一列存储数据量不可能太大)。

 

我的应用场景:优惠信息、购物车持久化(每个用户购物车最多50条)。

 

附件中的 performance.rar是测试用例,欢迎测试拍砖。。

下载地址:performance.rar 

                  hibernate.rar 

 


///

新场景补充///

///

购物车持久化:

1、用户没有登录:存储到cookie中

2、用户登录后:   存储到数据库中

 

分析:

 购物车是用户绑定的,一个用户一个

购物车最多只允许存50个(因为cookie大小有限)

 

实现:

1、关联表:购物车-----购物车明细,又是典型一对多,,需要频繁操作关联表

2、JSON:只要一张购物车表,用户数据通过JSON存数据库(如 [{productUuid:1, number:2}, {productUuid:2, number:2}])

 

使用JSON方式效率肯定是最高的,虽然有转换过程但是在内存中,比读写磁盘肯定快的多。看上边的测试用例。这种方式的好处不需要单独的关联表,省了一张表,何乐而不为。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值