您的位置:首页 > 数据库 > Redis

redis value为对象的排序、分页的一种实现

2014-09-18 16:24 501 查看
-------基于HBase存储引擎并实现了排序、分页的Redis缓存策略

思路:

1、 当前系统缓存json,根据key存取value,key 和value都是String类型,直接返回前端。

2、 考虑支持分页,想到了缓存排好序的ResultSet,每一次前端请求,将所有数据缓存到redis,根据filter返回某页的数据,此部分数据是封装好的json。

考虑到使用list会增加开发的工作量,所以暂不用。

3、 考虑缓存ResultSet对象,所以该类要实现序列化,用hadoop的Writable,不用java本身的Serializable。

4、 前端需求不需要分页的仍然用原来接口,缓存json,用不同的annotation设置到查询方法上区分。

注:ResultSet为自己实现了的将hbase列存储数据转为按关系数据库行存储的数据结构。

具体实现:

1、由于每次都传给前端少量数据,所以要传给前端总记录条数方便其确定分页信息,可封转在json里。

2、rediscache操作类增加支持序列化的存取方法:
@Override public ResultSet getResultSetCache(String key) { try { log.info("get object from redisCache :"+key); ShardedJedis jedis = pool.getResource(); ResultSet value = SerializableUtils.deSerialize(jedis.get(key.getBytes()), ResultSet.class); pool.returnResource(jedis); return value; } catch (Exception e) { e.printStackTrace(); } return null; }  @Override public boolean setResultSetCache(String key, ResultSet value) { try { log.info("add object to redisCache :"+key); ShardedJedis jedis = pool.getResource(); jedis.set(key.getBytes(),SerializableUtils.serialize(value)); pool.returnResource(jedis); return true; } catch (Exception e) { e.printStackTrace(); } return false; }


其中SerializableUtils工具类实现对writable子类的序列化、反序列化操作:
public class SerializableUtils {  public static<T extends Writable> byte[] serialize(Object value) throws IOException { ByteArrayOutputStream bos = new ByteArrayOutputStream();  DataOutputStream oos = new DataOutputStream(bos); if (value instanceof Writable) { ((T) value).write(oos); } else { throw new IOException("not instanceof Writable!"); } return bos.toByteArray(); }  public static <T extends Writable> T deSerialize(byte[] byteCode,Class<T> classType) throws IOException{ ByteArrayInputStream bis = new ByteArrayInputStream(byteCode); T object = null; try { DataInputStream dis = new DataInputStream(bis); object = (T)classType.newInstance(); object.readFields(dis); return object; } catch (IOException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); }  return null; }  }


java本身的序列化反序列化工具类:
public class SerializableUtil {  public static<T extends Serializable> byte[] serialize(Object value){ ByteArrayOutputStream bos = new ByteArrayOutputStream();  try { ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(value); } catch (IOException e) { e.printStackTrace(); } return bos.toByteArray(); }  public static <T extends Serializable> T deSerialize(byte[] bytes){ ByteArrayInputStream bIs = new ByteArrayInputStream(bytes); try { ObjectInputStream oIs = new ObjectInputStream(bIs); return (T)oIs.readObject(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } return null; } }


3、 增加两个annotation及两个切面处理类,annotation用以在具体查询方法上添加,区分需不需要排序,需要排序的缓存ResultSet,不需要的缓存Json。

需要分页的切面类主要代码:
String md5key = MD5Util.getMD5(filter.getValue().toString()); Object value = redisCacheManager.getResultSetCache(md5key); String srcClzzName = ""; boolean flag = false; if (null != value) { srcClzzName = pjp.getTarget().getClass().getSimpleName(); JSONObject json = redisCacheManager.getJson(value,filter,srcClzzName); return json; } else if ("null".equals(value)) { return null; } else { //执行hbase查询  ResultSet orderRs = redisCacheManager.getResultSet(filter,srcClzzName); boolean ifNeedCache = orderRs.size()>0?true:false; if (ifNeedCache == true){ redisCacheManager.setResultSetCache(md5key, orderRs); } return redisCacheManager.getJson(orderRs, filter, srcClzzName); }


getResultSet部分代码:
public ResultSet getOrderdResultSet(QueryFilter filter) {  SaleDetailsFilter Salefilter = (SaleDetailsFilter) filter; String shopId = Salefilter.getShopId(); String date = Salefilter.getDate();//  int proType = Salefilter.getProType();//  byte sku = 1, spu = 0; byte isSKU = Salefilter.getIsMergeSKU() ? spu : sku; long[] proNum = Salefilter.getProNums();//  String[] itemNums = Salefilter.getItemNums();//  ResultSet result = new ResultSet();  try { // set start row; ByteBuffer rowkey = ByteBuffer.allocate(13); rowkey.putInt(Integer.parseInt(shopId)); rowkey.putInt(Integer.parseInt(date)); // set product type, default 0 rowkey.putInt(proType); rowkey.put(isSKU); byte[] endkey = CommonUtil.getEndKey(rowkey.array(),"int,int,int,byte");  Where where = null; List<OrderBy> orderlist = null;  if ((proNum != null && proNum.length > 0)) {根据前端传入的商品id查询记录 //拼where条件  for (int i = 0; i < proNum.length; i++) { if(i>0){ where = or(eq("d:ProID",proNum[i]),where); continue; } where = eq("d:ProID",proNum[i]); } orderlist = new ArrayList<OrderBy>(); Map<String,Integer> ordermap = Salefilter.getOrderBy(); if(null!=ordermap){ Set<String> keys = ordermap.keySet(); for(Iterator<String> it = keys.iterator();it.hasNext();){ String key = it.next(); Integer value = ordermap.get(key); if(value==0){ orderlist.add(asc(key)); }else if(value==1){ orderlist.add(desc(key)); } } result = client.simpleQuery(rowkey.array(),endkey, select, tableName, where, orderlist,-1); }else{ result = client.simpleQuery(rowkey.array(),endkey, select, tableName, where, null,-1); } return result; } else if (itemNums != null && itemNums.length > 0) {  .....	 } else { ......	 }  } catch (Exception e) { logger.error(e.getMessage(), e); } catch (Throwable e) { logger.error(e.getMessage(), e); e.printStackTrace(); } return null; }


当然,用到的很多方法在cp基础上自定义的对hbase的查询接口。

4、 查询接口类增加相应属性、方法,并且hbase表要加入coprocessor的支持,因为用到了聚合查询。

从缓存得到某一页的数据返回前端:
public JSONObject getPagedJson(Object value, QueryFilter filter,String srcClzzName) throws JSONException {  JSONObject result = new JSONObject(); ResultSet tempRs = (ResultSet) value; long size = tempRs.size(); ResultSet realRs = new ResultSet();  SaleDetailsFilter sdf = (SaleDetailsFilter) filter; int pageNum = sdf.getPageNum(); int start = (pageNum - 1) * PAGE; int maxend = PAGE * pageNum-1; long end = size-(PAGE*pageNum)>=0?maxend:start+size-(pageNum-1)*PAGE-1; for (int i = start; i <= end; i++) { realRs.add(tempRs.get(i)); } JSONObject temp = new JSONObject(); if (realRs.size() > 0) { temp = trans.toJSONObject(realRs,select); } result.put(Transformer.DTL, temp); result.put(Transformer.SIZE, size); return result; }


5、 查询接口类对应的filter增加两个属性,orderby和pageNum。Orderby表示排序的列,map类型,key表示列,值为0或1,表示升序或降序,默认为空,表示不排序。PageNum表示页号,默认第一页。

并将orderby纳入到查询条件中作为生成redis key的json。

pageNum是不能纳入的,因为前端翻页时应该对应redis中的一份数据。redis中的数据的份数由查询的种类决定,每一份都是查询的全量数据。后续考虑用list或索引的方式实现。

6、 redis集群安装—略。

7、 redis java客户端配置文件在web-inf下,包括连接池配置,属性配置,切面配置。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: