1.引入jar包
jedis-2.9.0.jar
spring-data-redis-1.7.11.RELEASE.jar
2.redis配置文件
缓存管理器中我set了两个模块,分别叫selectUserInfo和selectRole,设置过期时间为120秒,这两个模块接下来会用到,com.caodaxing.redis.cache.MyCache为实现Cache接口的自定义实现类,
下面为缓存自定义实现类代码:
@Component
public class MyCache implements Cache {
@Autowired
private RedisTemplate redisTemplate;
private String name;
private long timeout;
@Override
public String getName() {
return this.name;
}
@Override
public Object getNativeCache() {
return this.redisTemplate;
}
@Override
public ValueWrapper get(Object key) {
if(key == null || StringUtils.isEmpty(key.toString())) {
return null;
}else {
final String finalKey = formatStr(key);
redisTemplate.multi();
Object object = redisTemplate.execute(new RedisCallback
记住存储对象时,一定要序列化,不然会报错,name为配置文件中的配置,getNativeCache()方法为设置你的缓存对象,我这里用的是redis,当然你也集成mongo和memcache等,timeout为设置数据的过期时间.
3.缓存方法
下面是我对service层中两个方法进行缓存
@Service
public class LoginUserServiceImpl implements LoginUserService {
@Autowired
private LoginUserMapper loginUserMapper;
/**
* 调用该方法时,会先触发Cache接口的get方法,如果缓存中查到数据,则直接返回数据,不再走该方法
* 如果没有查到数据,执行该方法,结束后调用Cache接口的put方法,将返回的数据存入缓存中
* 注意:key的值是字符串的话,使用单引号括起来,例:key="'userName'",如果不加单引号默认做Spel表达式识别
* 会报SpelEvaluationException错误,spel表达式:#方法参数
*/
@Cacheable(value="selectUserInfo",key="'userinfo_'+#pageNumber")
@Override
public List getUserInfoList(int pageNumber) {
System.out.println("select userInfo start...");
return getUser(pageNumber);
}
/**
* 删除缓存数据,value为要删除的哪个模块数据,key为要删除的数据键值,调用Cache类的evict方法
* 当allEntries为true时,删除value模块里的所有数据,调用Cache类的clear方法,key可不填
* allEntries默认为false,此时key值必填,否则会以默认key查询,有可能报错
*/
@CacheEvict(value="selectUserInfo",key="'userinfo_1'",allEntries=false)
@Override
public void clearData() {
System.out.println("clear all data...");
}
private List getUser(int pageNumber) {
System.out.println("query database");
LoginUserExample example = new LoginUserExample();
example.setOrderByClause(" id asc limit "+((pageNumber-1)*1)+","+(pageNumber*1));
List selectByExample = loginUserMapper.selectByExample(example);
return selectByExample;
}
}
可以看到,我在方法的上面加入spring自带的@Cacheable和@CacheEvict注解,并且用到了上面配置文件中配置的name,我这里是将从数据库查询的用户信息放入名字为"selectUserInfo"模块的redis缓存中,key为"userinfo_"加当前页pageNumber参数
对于spring缓存注解不了解的可百度一下,这里就不多做介绍了,在这说一下该类中两个方法与上面自定义缓存类的联系,当调用getUserInfoList()方法的时候,会先调用Cache类中的get()方法,根据key值查询是否有数据,如果有,则直接返回数据,不执行getUserInfoList()方法中的代码,如果没有查到数据,则执行该方法中的代码,在方法执行完成后,会调用Cache类中的put()方法,将返回的数据放入到redis缓存中,这就是@Cacheable注解执行的全过程,
另外再讲下@CachePut注解,它在方法执行完后直接调用Cache类中的put()方法,不会调用get()方法,用于更新数据等使用
至于@CacheEvict注解,为清除数据使用,它有两种情况,当你配置allEntries=true时,他执行的是Cache类中的clear()方法,为false时,执行evict()方法,具体使用哪种情况,可根据需要自行选择.
到这里spring集成redis做缓存就讲到这里了,下面我们讲一下集成redis出现的连接池错误:
一般使用redis连接池后,系统会帮你分配资源以及管理连接,但是当你打开了redis的事务时,有事务的连接池是不会自动关闭redis对象连接的,需自己手动关闭并释放连接,而且想要事务生效必须使用RedisTemplate中的multi()和exec()包住,如上面代码所示:
至于手动关闭连接,回收到redis连接池中可在exec()方法之后使用
RedisConnectionUtils.unbindConnection(redisTemplate.getConnectionFactory());
具体是否有用没有测试,可以参考:https://blog.csdn.net/LiuHanFanShuang/article/details/52136438
还有一种情况会报跟连接池相关的错误,但并不是连接数满了,而是强制关闭Redis快照导致不能持久化。
这种情况我们只需要在redis服务器上执行以下代码就可:
127.0.0.1:6379> CONFIG SET stop-writes-on-bgsave-error no