精华帖 (4) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (1)
|
|
---|---|
作者 | 正文 |
发表时间:2012-04-25
最后修改:2012-05-10
一、场景public class OrderModel { private List<String> favorableDescList; }
订单中会存储一些优惠信息,方便页面展示时使用,如: 1、满100减50 2、参与【老会员真情回馈——精品课程体验活动】,仅需支付200.00学币 3、【Oracle + PL/SQL 实战】套装课程的【抢购】活动,优惠120.00学币 ……等等
如图所示,我们在页面给用户展示他们参与的优惠信息: 二、分析如上优惠信息有如下特点: 1、只用于展示,不会涉及修改; 2、一旦订单支付成功,不会再改变; 3、数据量不会很大。 4、此处不会分析统计这些数据,只是展示使用,注意场景。
限制:不可能进行统计/分析查询。 三、解决方案1、最简单的解决方案是关联表:
2、JSON解决方案:
通过如上思路我们可以解决许多类似的问题。
3、代码示例:
1、模型类: public class OrderModel { @Type(type = "cn.javass.framework.hibernate.type.JsonType") //① private List<String> favorableDescList; } ①处使用我们自定义的Hibernate类型来进行转换,上边代码只有一部分
2、自定义JsonType package cn.javass.framework.hibernate.type; //省略import public class JsonType implements UserType, Serializable { private String json; @Override public int[] sqlTypes() { return new int[] {Hibernate.STRING.sqlType()}; } @Override public Class returnedClass() { return JsonList.class; } @Override public boolean equals(Object o, Object o1) throws HibernateException { if (o == o1) { return true; } if (o == null || o == null) { return false; } return o.equals(o1); } @Override public int hashCode(Object o) throws HibernateException { return o.hashCode(); } /** * 从JDBC ResultSet读取数据,将其转换为自定义类型后返回 * (此方法要求对克能出现null值进行处理) * names中包含了当前自定义类型的映射字段名称 * @param resultSet * @param names * @param owner * @return * @throws HibernateException * @throws SQLException */ @Override public Object nullSafeGet(ResultSet resultSet, String[] names, Object owner) throws HibernateException, SQLException { String json = resultSet.getString(names[0]); if(json == null || json.trim().length() == 0) { return new JsonList(); } return JSONArray.toList(JSONArray.fromObject(json), JsonList.class); } /** * 本方法将在Hibernate进行数据保存时被调用 * 我们可以通过PreparedStateme将自定义数据写入到对应的数据库表字段 * @param preparedStatement * @param value * @param i * @throws HibernateException * @throws SQLException */ @Override public void nullSafeSet(PreparedStatement preparedStatement, Object value, int i) throws HibernateException, SQLException { if(value == null) { preparedStatement.setNull(i, Hibernate.STRING.sqlType()); } else { preparedStatement.setString(i, JSONArray.fromObject(value).toString()); } } /** * 提供自定义类型的完全复制方法 * 本方法将用构造返回对象 * 当nullSafeGet方法调用之后,我们获得了自定义数据对象,在向用户返回自定义数据之前, * deepCopy方法将被调用,它将根据自定义数据对象构造一个完全拷贝,并将此拷贝返回给用户 * 此时我们就得到了自定义数据对象的两个版本,第一个是从数据库读出的原始版本,其二是我们通过 * deepCopy方法构造的复制版本,原始的版本将有Hibernate维护,复制版由用户使用。原始版本用作 * 稍后的脏数据检查依据;Hibernate将在脏数据检查过程中将两个版本的数据进行对比(通过调用 * equals方法),如果数据发生了变化(equals方法返回false),则执行对应的持久化操作 * * @param o * @return * @throws HibernateException */ @Override public Object deepCopy(Object o) throws HibernateException { if(o == null) return null; JsonList jsonList = new JsonList(); jsonList.addAll((List)o); return jsonList; } /** * 本类型实例是否可变 * @return */ @Override public boolean isMutable() { return true; } /* 序列化 */ @Override public Serializable disassemble(Object value) throws HibernateException { return ((Serializable)value); } /* 反序列化 */ @Override public Object assemble(Serializable cached, Object owner) throws HibernateException { return cached; } @Override public Object replace(Object original, Object target, Object owner) throws HibernateException { return original; } } JSON框架使用的是json-lib 2.1。
3、自定义JsonList package cn.javass.framework.hibernate; public class JsonList<T> extends ArrayList implements Cloneable { }
就这么简单,欢迎大家讨论。
订单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是测试用例,欢迎测试拍砖。。
/////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////新场景补充/////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////////// 购物车持久化: 1、用户没有登录:存储到cookie中 2、用户登录后: 存储到数据库中
分析: 购物车是用户绑定的,一个用户一个 购物车最多只允许存50个(因为cookie大小有限)
实现: 1、关联表:购物车-----购物车明细,又是典型一对多,,需要频繁操作关联表 2、JSON:只要一张购物车表,用户数据通过JSON存数据库(如 [{productUuid:1, number:2}, {productUuid:2, number:2}])
使用JSON方式效率肯定是最高的,虽然有转换过程但是在内存中,比读写磁盘肯定快的多。看上边的测试用例。这种方式的好处不需要单独的关联表,省了一张表,何乐而不为。
===================================================== ====================SQL反模式========================== ===================================================== 2012-5-10 8:43
买了本《SQL反模式》,第二章内容是:乱穿马路,和我的场景类似:
本书提出的反模式是:格式化的逗号分隔列表,这种方式存在的问题: 1、查找指定的产品(即查找列表中的某一个,无法用索引) 2、聚合(需要分割进行聚合,相当麻烦) 3、更新(如果用我提到的JSON方式就简单了,直接更新JSON对应的对象即可) 4、列表长度限制(需要考虑) 5、合适的分隔符(JSON方式无需考虑)
这是一种反规范化的使用,在无需根据列表项查询时还是很好的场景(避免连表查询)
具体内容可以参考《SQL反模式》 第二章
声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2012-04-25
使用nosql很容易就解决了
|
|
返回顶楼 | |
发表时间:2012-04-25
java_user 写道 使用nosql很容易就解决了
这个只是一种场景,可以这么使用,没有必要动用nosql,用纯关系数据库也可解决,此处只是换一种思路来解决问题。 |
|
返回顶楼 | |
发表时间:2012-04-25
这样频繁的转换性能开销会否太大
|
|
返回顶楼 | |
发表时间:2012-04-25
最后修改:2012-04-25
为什么姐每维护一个网站、系统,感觉你们je人写的代码都很垃级的?搞得姐都无能为力去维护。是je的问题还是je人的问题。。。。。
|
|
返回顶楼 | |
发表时间:2012-04-25
superyang 写道 为什么姐每维护一个网站、系统,感觉你们je人写的代码都很垃级的?搞得姐都无能为力去维护。是je的问题还是je人的问题。。。。。
因为你牛B |
|
返回顶楼 | |
发表时间:2012-04-25
修改怎么搞?
|
|
返回顶楼 | |
发表时间:2012-04-25
最后修改:2012-04-26
downpour 写道 修改怎么搞?
我这个不会修改 (因为是显示一些优惠信息 一旦提交了订单是不会变的,而且都是在订单展示时伴随显示,而且不会进行统计分析,所以这个地我就没搞一张关联表来实现,直接通过JSON方式存取) 如果修改跟普通方式一样啊,修改List(在更新时自动转换成JSON保存到数据库),比如我的购物车持久化场景 就是修改list 这种方式限制: 不可能进行统计/分析查询。 从我现在遇到的情况 只有这一种情况(优惠信息) 适合,所以应用场景较少。 |
|
返回顶楼 | |
发表时间:2012-04-25
dieslrae 写道 这样频繁的转换性能开销会否太大
连表不也需要开销吗? 对不 连表的开销大 还是转换的开销大,虽然我没有测试用例 但我可以肯定 不连表肯定比连表消耗的时间多 而且此处我不是为了考虑性能,而是少写了一张表 |
|
返回顶楼 | |
发表时间:2012-04-25
最后修改:2012-04-25
安全套接字层不
|
|
返回顶楼 | |