第一次写博客,好紧张~~
最近在学习Redis,需求是将之前做的一个小型商城的一些数据放入Redis缓存中,避免每次都频繁的去数据库查询,降低效率。
属于摸索阶段,只能勉强实现功能,其中可能会有些有问题的地方,希望看到这篇文章的大佬能指出纠正。
5.0.6.RELEASE
5.2.6.Final
我使用的都是目前最新的版本
整合Redis所需的依赖
redis.clients jedis 2.9.0 org.springframework.data spring-data-redis 2.0.1.RELEASE
在使用注解模式之前,我是使用编码方式完成了所需功能,下面把这种方式也说一下吧。
application-redis.xml配置文件
Spring的主配置文件就不贴了,不使用缓存注解模式的话就没有需要添加的地方,就是一个普通的Spring+Hibernate的整合文件。
配置完成后就可以开始编写代码了,其实逻辑很简单,访问的时候先通过Key判断缓存中是否存在数据,存在就直接取出数据转换格式后返回,不存在就进入数据库查询再放入缓存,返回数据。
我以我的需求为例,我目前需要将首页的广告放入缓存,从缓存中获取,因为这些资源是公开的,对所有人可见的,不必每次去数据库查询回来,所以放在缓存最合适,提高效率。
这是我的ADServiceImpl中实现获取的方法
@Override public List
findAllByType() { try { //去缓存中查 String adList = redisServiceImpl.get("adList"); //不为null if (!WoUtil.isEmpty(adList)) { List ads = JSONArray.parseArray(adList,AD.class); //直接返回数据 return ads; } }catch (Exception e) { e.printStackTrace(); } //缓存中不存在,就进入数据库查询,这是我自己封装的一个BaseDao的根据条件查询的方法 List adList = adDaoImpl.findAllBy(new HashMap (){ { this.put("type",AD_TYPE); } }); try { //从数据库查出后转换类型再放入缓存 String jsonStr = JSONArray.toJSONString(adList); redisServiceImpl.set("adList",jsonStr); }catch (Exception e) { e.printStackTrace(); } return adList; } 我这里使用的alibaba提供的fastJson,让对象和字符串之间可以轻松转换,不用使用序列化和反序列化了。
使用try{}catch{}保证缓存操作出问题不会影响正常的查询功能。
上面这样就可以完成对redis的操作了,但当我写完第一个后问题就来了,我不止广告需要存入缓存,还有其他很多地方都需要存入,比如商品分类和商品这些,那我不是都要在他们的Service加上这些代码?而且不难看出,这些代码可以说都是重复的 。
(⊙o⊙)…我使用的idea,设置了下背景,还是很好看的吧。。。。。
这两部分不是我们实际需要的代码,所以看起来很臃肿,一点也不优雅。
如果每一个Service都这样写那也太麻烦了吧,所以我找了些注解模式的文章学习,使用注解的话,配置文件中就需要添加一些东西了。
application-redis.xml,在刚才的基础上添加内容
//操作缓存的实现类 //这里的value就是使用注解时使用的,用来找到name然后进入到缓存的实现类 //这里根据我的需求直接返回的时候就是我需要的类型,所以传一个type //根据需求给缓存实现类添加属性,比如过期时间,我这里暂时不用 <-- --> 在这里我使用的是
org.springframework.cache.support.SimpleCacheManager;
网上很多都是用的
org.springframework.data.redis.cache.RedisCacheManager.
我使用另一个会一直报错,找了很久也没找到问题的原因,希望有大佬能告诉我。
这个必须在spring的主配置文件中,cache-manager的名字必须和application-redis中的cacheManager一致
然后开始编写操作缓存的实现类
//实现Cache接口 public class RedisCache
implements Cache { //缓存的名称 private String name; //返回的类型 private Class type; //Spring提供的操作Reids的工具 private RedisTemplate redisTemplate; public void setName(String name) { this.name = name; } public RedisTemplate getRedisTemplate() { return redisTemplate; } public Class getType() { return type; } public void setType(Class type) { this.type = type; } public void setRedisTemplate(RedisTemplate redisTemplate) { this.redisTemplate = redisTemplate; } @Override public String getName() { return this.name; } @Override public Object getNativeCache() { return this.redisTemplate; } //通过key查询缓存 @Override public ValueWrapper get(Object key) { if (WoUtil.isEmpty(key)) { return null; }else { final String finalKey; if (key instanceof String) { finalKey = (String) key; }else { finalKey = key.toString(); } Object object = null; object = redisTemplate.execute(new RedisCallback 这里面最主要的就是put和get方法,我只实现了put和get和一个evict就目前够用了,方法逻辑很简单,判断key是否为空,不为空就调用对应的方法,因为我都是获取的List,所有返回的是List,根据的自己的需求编写。
下面就是如何使用了,我以商品为例
//value对应redis配置中的value //key只要保证唯一就可以了,我这里用的root获取当前被调用的对象的Class @Override @Cacheable(value = "goodsCache", key = "#root.targetClass") public List
getList() { List goodsList = goodsDaoImpl.findAll(); return goodsList; } 这样看起来代码就很优雅了,里面只有我们真正需要的代码了。
Spring提供的root对象的使用
属性名称
描述
示例
methodName
当前方法名
#root.methodName
method
当前方法
#root.method.name
target
当前被调用的对象
#root.target
targetClass
当前被调用的对象的class
#root.targetClass
args
当前方法参数组成的数组
#root.args[0]
caches
当前被调用的方法使用的Cache
#root.caches[0].name
第一次写博客,逻辑很乱,只会把自己做的东西给大家看看,也没怎么分析,实在是抱歉,有时间会多写写锻炼自己的。