使用redis和fastjson做应用和mysql之间的缓存
第一次做這種javaweb的項目,難免還是要犯很多錯誤。
大概也知道,redis常常被用來做應用和mysql之間的緩存。模型大概是這樣子的。
為了讓redis能夠緩存mysql數據庫中的數據,我寫了很多這樣類似的代碼:
原來的查詢商品
public Product selectProductById(int id) {Product product = productMapper.selectByPrimaryKey(id);if (product != null) {String detail = product.getDetail();if (detail != null) {product.setDetail(HtmlUtils.string2Html(detail));// 進行html轉義,替換html轉義符}}return product; }用redis緩存之后的查詢商品
public Product selectProductById(int id) {Product product = JSONObject.parseObject(redisCli.get(PRODUCT_KEY + id), Product.class);if (product != null) {product = productMapper.selectByPrimaryKey(id);String detail = product.getDetail();if (detail != null) {product.setDetail(HtmlUtils.string2Html(detail));// 進行html轉義,替換html轉義符}redisCli.set(PRODUCT_KEY + product.getId(), JSONObject.toJSON(product).toString(),30);}return product; }老板說,不行啊,網站首頁太慢了!于是我們又開始在ModelAndView上做文章。
原來首頁的代碼
于是我們又加了這樣的代碼:
@RequestMapping("/wxIndex/{id}") public ModelAndView goWxIndex(HttpServletRequest request, HttpServletResponse response,@PathVariable(value = "id") Integer id) {ModelAndView mv = JSONObject.parseObject(redisCli.get("index"),ModelAndView.class);if(mv != null){return mv;}mv = new ModelAndView();mv.setViewName(ViewNameConstant.WXINDEX); //一些邏輯代碼redisCli.put("index",JSONObject.toString(mv),30);return mv; }于是代碼越來越亂。
慢慢學習和適應spring的思想中,明白,我們可以使用攔截的方式去做mysql的緩存。我們攔截到一個sql語句,于是把這條sql語句作為key,把返回的結果作為value保存到redis里面去,失效時間為30秒鐘;
期間如果發現一個有insert或者update就把對應表的所有的緩存給清理掉。
有了思想就下手去做好了。不曾想發現mybatis已經提供了對應好的緩存的接口Cache,思想和上述完全一致。
那么我們也就是用他的接口好了。
mybatis默認緩存是PerpetualCache,可以查看一下它的源碼,發現其是Cache接口的實現;那么我們的緩存只要實現該接口即可。
該接口有以下方法需要實現:
public abstract interface CacheString getId();int getSize();void putObject(Object key, Object value); Object getObject(Object key); Object removeObject(Object key);void clear();ReadWriteLock getReadWriteLock(); }最重要的兩個接口是putObject和getObject;任何select語句都會首先請求getObject函數,如果返回為null,那么再去請求mysql數據庫;我們在mysql中取到數據之后,調用putObject函數,進行緩存數據的保存。
序列圖為:
網上提供的案例,大部分是這樣子:
public class MybatisRedisCache implements Cache {private RedisCli redisCli;@Override??public?void?putObject(Object?key,?Object?value)?{??logger.debug(">>>>>>>>>>>>>>>>>>>>>>>>putObject:"+key+"="+value);??redisCli.set(SerializeUtil.serialize(key.toString()),?SerializeUtil.serialize(value));??}??@Override??public?Object?getObject(Object?key)?{??Object?value?=?SerializeUtil.unserialize(redisCli.get(SerializeUtil.serialize(key.toString())));??logger.debug(">>>>>>>>>>>>>>>>>>>>>>>>getObject:"+key+"="+value);??return?value;??}?? }public?class?SerializeUtil?{??public?static?byte[]?serialize(Object?object)?{??ObjectOutputStream?oos?=?null;??ByteArrayOutputStream?baos?=?null;??try?{??//序列化??baos?=?new?ByteArrayOutputStream();??oos?=?new?ObjectOutputStream(baos);??oos.writeObject(object);??byte[]?bytes?=?baos.toByteArray();??return?bytes;??}?catch?(Exception?e)?{??e.printStackTrace();??}??return?null;??}??public?static?Object?unserialize(byte[]?bytes)?{??ByteArrayInputStream?bais?=?null;??try?{??//反序列化??bais?=?new?ByteArrayInputStream(bytes);??ObjectInputStream?ois?=?new?ObjectInputStream(bais);??return?ois.readObject();??}?catch?(Exception?e)?{??}??return?null;??}? }?如果是通過java提供的序列化進行實體類和String的轉換,那么我們要修改所有已經存在的實體Bean類,工作量太大;而且java的序列化效率又低;我們還是考慮使用工程已經引入的fastjson好;使用fastjson,就必須在緩存數據的時候,同時緩存數據的類型;我們使用redis的hash結構,就能解決這個問題
于是接口就成了下面這個樣子:
public class MybatisRedisCache implements Cache {private RedisCli redisCli;@Overridepublic void putObject(Object key, Object value) {String keyStr = getKey(key);Map<String,String> map = new HashMap<String,String>();//如果是多組數據,那么保存的方式不同,多組的情況需要保存子實體類型if(value.getClass().equals(ArrayList.class)){@SuppressWarnings("unchecked")List<Object> list = (List<Object>)value;map.put("type", "java.util.ArrayList");if(list.size() > 0){map.put("subType", list.get(0).getClass().getCanonicalName());}else{map.put("subType",Object.class.getCanonicalName());}map.put("value", JSONObject.toJSONString(value));}else{map.put("type", value.getClass().getCanonicalName());map.put("value", JSONObject.toJSONString(value));}this.redisCli.hAllSet(keyStr, map,30);this.cacheKeys.add(keyStr);}@Overridepublic Object getObject(Object key) {try{String keyStr = getKey(key);Map<Object,Object> map = this.redisCli.hAllGet(keyStr);String type = (String)map.get("type");String value = (String)map.get("value");if(type == null || value == null){return null;}if("java.util.ArrayList".equals(type)){String subType = (String)map.get("subType");return JSONObject.parseArray(value, Class.forName(subType));}else{return JSONObject.parseObject(value, Class.forName(type));}}catch (Exception e){e.printStackTrace();return null;}}@Overridepublic void clear() {if(this.cacheKeys.isEmpty()){return ;} for(String key : this.cacheKeys){this.redisCli.del(key);}this.cacheKeys.clear();} }ps: 我們這里還是把key直接保存在了內存里面,這樣存在的問題就是,如果服務器重啟,那么需要清理所有的緩存;不然一定會造成臟數據。
或者,我們在保存緩存數據的時候,設置緩存數據的生命時間是30秒即可,希望對大家有所幫助。
轉載于:https://www.cnblogs.com/archy_yu/p/5276153.html
總結
以上是生活随笔為你收集整理的使用redis和fastjson做应用和mysql之间的缓存的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Angularjs与weui的握手
- 下一篇: 新手安装linux的磁盘划分