大體流程是從Service層獲取數據,先通過Redis,若是Redis沒有數據再去查詢db,最後把數據塞回到Redis。redis
看似很簡單的一個步驟,實際能夠寫出不一樣風格的方式。通常來講首先想到的無非是下面這樣(面向過程的僞代碼):緩存
Object val = redisutils.get("key"); if(val == null || val == ""){ Object obj = userdaoMapper.getUserById("key");
BeanUtils.cover(obj,User.class); }else{ return val; }
上面的僞代碼一看通俗易懂,可是在實際開發中,特別是多模塊開發的場景下大量充斥着如上的代碼的話那麼維護起來是一件費勁的事情,不只要編寫大量的重複代碼,還要對不一樣的實體類型進行一個轉換,那麼有什麼辦法能夠避免這個問題呢?第一個辦法想到的就是熟悉AOP,但在這裏不打算介紹AOP,而是如博客標題所示(經過抽象泛型模板)。app
public abstract class CacheWorker<P, R> { private static Log logger = LogFactory.getLog(CacheWorker.class); @Autowired protected RedisUtil redisUtil; /** * get方式獲取緩存 * * @param params 查詢參數 * @param expireSeconds 緩存過時時間 * @return 結果 * @throws SQLException */ @SuppressWarnings("unchecked") public R get(P params, Class<R> clazz) { // 獲取key,由子類實現 String key = getKey(params); Object res = getCache(key, clazz); // 若是緩存中存在,直接返回 if (res != null) { if (logger.isDebugEnabled()) { StringBuilder sb = new StringBuilder(); sb.append("從redis獲取數據 (key:{").append(key).append("})"); logger.debug(sb.toString()); } return (R) res; } if (logger.isDebugEnabled()) { StringBuilder sb = new StringBuilder(); sb.append("從redis獲取數據失敗(key:{").append(key).append("}), 準備從DB獲取."); logger.debug(sb.toString()); } // 不然去DB中取 R dataFromDb = getDataWhenNoCache(params); // 回寫cache if (dataFromDb != null) { setCache(getExpireSeconds(), key, dataFromDb); } return dataFromDb; } /** * 獲取過時時間 * * @return */ protected abstract int getExpireSeconds(); /** * set操做 設定緩存 * * @param expireSeconds * @param key * @param dataFromDb */ protected void setCache(int expireSeconds, String key, R dataFromDb) { redisUtil.set(key, dataFromDb, expireSeconds); } /** * set操做 從緩存中取值 * * @param key * @return */ protected Object getCache(String key, Class<R> clazz) { // 嘗試獲取緩存值 return redisUtil.get(key, clazz); } public void del(P params) { // 獲取key,由繼承者拼接 String key = getKey(params); redisUtil.delete(key); } /** * 當獲取不到緩存時,使用該方法去DB或其餘途徑取數據 * * @param params * @return * @throws SQLException */ protected abstract R getDataWhenNoCache(P params); /** * 獲取key * * @param params * @return */ protected abstract String getKey(P params);
@Component public class GoodsInfoCacheWorker extends CacheWorker<Integer, Goods> { @Autowired private GoodsMapper goodsMapper; @Override protected Goods getDataWhenNoCache(Integer goodsId) { return goodsMapper.selectByPrimaryKey(goodsId); } @Override protected String getKey(Integer goodsId) { String key = MessageFormat.format(CommonConstant.RedisKey.GOODS_INFO_BY_ID, new Object[] { goodsId }); return key; } @Override protected int getExpireSeconds() { return CommonConstant.RedisKeyExpireSeconds.GOODS_STORE_BY_ID; } }
@Autowired private GoodsInfoCacheWorker goodsInfoCacheWorker; public String getGoodsRandomName(Integer goodsId) { Goods goods = goodsInfoCacheWorker.get(goodsId, Goods.class); long now = System.currentTimeMillis(); // 已經開始了活動,則輸出搶購連接 if (goods.getStartTime().getTime() < now && now < goods.getEndTime().getTime()) { return goods.getRandomName(); } return StringUtils.EMPTY; }
·dom