手动的操作缓存自己解决了,原本想着以后就用手动的方式,可是不研究研究注解感觉自己错过了什么,现在弄完了,感觉真是简单,比手动的方式简单太多了,可能是我直接用的别人的工具类可能简单,如果手动的方式中redisDao命令全了,可能会感觉差不多,不过还是有点区别的,不是很大,看你的需求了
手动方式操作redis请看这:https://blog.csdn.net/weixin_43113679/article/details/90413124
现在先看目录结构
特别解释一下:cn.qlq.util是redis的工具包,里面的基本不需要改变
目前就算要修改也就有两个地方需要修改
1、修改key的生命周期
2、修改key的格式
现在直接开始部署xml
使用的java类
RedisCacheConfig.java
package cn.qlq.util;
import java.lang.reflect.Method;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
@EnableCaching
@Configuration
public class RedisCacheConfig extends CachingConfigurerSupport {
private volatile JedisConnectionFactory jedisConnectionFactory;
private volatile RedisTemplate<String, String> redisTemplate;
private volatile RedisCacheManager redisCacheManager;
public RedisCacheConfig() {
super();
}
/**
* 带参数的构造方法 初始化所有的成员变量
*
* @param jedisConnectionFactory
* @param redisTemplate
* @param redisCacheManager
*/
public RedisCacheConfig(JedisConnectionFactory jedisConnectionFactory, RedisTemplate<String, String> redisTemplate,
RedisCacheManager redisCacheManager) {
this.jedisConnectionFactory = jedisConnectionFactory;
this.redisTemplate = redisTemplate;
this.redisCacheManager = redisCacheManager;
}
public JedisConnectionFactory getJedisConnecionFactory() {
return jedisConnectionFactory;
}
public RedisTemplate<String, String> getRedisTemplate() {
return redisTemplate;
}
public RedisCacheManager getRedisCacheManager() {
return redisCacheManager;
}
@Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
//规定 本类名-方法名-参数名 为key(这个是没有自己指定key的时候,自己默认生成的)
@Override
public Object generate(Object o, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
sb.append(o.getClass().getName());
sb.append("-");
sb.append(method.getName());
sb.append("-");
for (Object param : params) {
sb.append(param.toString());
}
return sb.toString();
}
};
}
}
KeyGenerator的generate是当你没有指定key的时候,它会根据规则进行自己生成,redis用的好,有一个关键就是key要设置的强大
RedisUtil.java
package cn.qlq.util;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
/**
*
* @author QLQ
* 基于spring和redis的redisTemplate工具类
* 针对所有的hash 都是以h开头的方法
* 针对所有的Set 都是以s开头的方法 不含通用方法
* 针对所有的List 都是以l开头的方法
*/
@Component//交给Spring管理(在需要缓存的地方自动注入即可使用)
public class RedisUtil {
@Autowired//(自动注入redisTemplet)
private RedisTemplate<String, Object> redisTemplate;
public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}
//=============================common============================
/**
* 指定缓存失效时间
* @param key 键
* @param time 时间(秒)
* @return
*/
public boolean expire(String key,long time){
try {
if(time>0){
redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 根据key 获取过期时间
* @param key 键 不能为null
* @return 时间(秒) 返回0代表为永久有效
*/
public long getExpire(String key){
return redisTemplate.getExpire(key,TimeUnit.SECONDS);
}
/**
* 判断key是否存在
* @param key 键
* @return true 存在 false不存在
*/
public boolean hasKey(String key){
try {
return redisTemplate.hasKey(key);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 删除缓存
* @param key 可以传一个值 或多个
*/
@SuppressWarnings("unchecked")
public void del(String ... key){
if(key!=null&&key.length>0){
if(key.length==1){
redisTemplate.delete(key[0]);
}else{
redisTemplate.delete(CollectionUtils.arrayToList(key));
}
}
}
//============================String=============================
/**
* 普通缓存获取
* @param key 键
* @return 值
*/
public Object get(String key){
return key==null?null:redisTemplate.opsForValue().get(key);
}
/**
* 普通缓存放入
* @param key 键
* @param value 值
* @return true成功 false失败
*/
public boolean set(String key,Object value) {
try {
redisTemplate.opsForValue().set(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 普通缓存放入并设置时间
* @param key 键
* @param value 值
* @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
* @return true成功 false 失败
*/
public boolean set(String key,Object value,long time){
try {
if(time>0){
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
}else{
set(key, value);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 递增
* @param key 键
* @param by 要增加几(大于0)
* @return
*/
public long incr(String key, long delta){
if(delta<0){
throw new RuntimeException("递增因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, delta);
}
/**
* 递减
* @param key 键
* @param by 要减少几(小于0)
* @return
*/
public long decr(String key, long delta){
if(delta<0){
throw new RuntimeException("递减因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, -delta);
}
//================================Map=================================
/**
* HashGet
* @param key 键 不能为null
* @param item 项 不能为null
* @return 值
*/
public Object hget(String key,String item){
return redisTemplate.opsForHash().get(key, item);
}
/**
* 获取hashKey对应的所有键值
* @param key 键
* @return 对应的多个键值
*/
public Map<Object,Object> hmget(String key){
return redisTemplate.opsForHash().entries(key);
}
/**
* HashSet
* @param key 键
* @param map 对应多个键值
* @return true 成功 false 失败
*/
public boolean hmset(String key, Map<String,Object> map){
try {
redisTemplate.opsForHash().putAll(key, map);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* HashSet 并设置时间
* @param key 键
* @param map 对应多个键值
* @param time 时间(秒)
* @return true成功 false失败
*/
public boolean hmset(String key, Map<String,Object> map, long time){
try {
redisTemplate.opsForHash().putAll(key, map);
if(time>0){
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
* @param key 键
* @param item 项
* @param value 值
* @return true 成功 false失败
*/
public boolean hset(String key,String item,Object value) {
try {
redisTemplate.opsForHash().put(key, item, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
* @param key 键
* @param item 项
* @param value 值
* @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
* @return true 成功 false失败
*/
public boolean hset(String key,String item,Object value,long time) {
try {
redisTemplate.opsForHash().put(key, item, value);
if(time>0){
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 删除hash表中的值
* @param key 键 不能为null
* @param item 项 可以使多个 不能为null
*/
public void hdel(String key, Object... item){
redisTemplate.opsForHash().delete(key,item);
}
/**
* 判断hash表中是否有该项的值
* @param key 键 不能为null
* @param item 项 不能为null
* @return true 存在 false不存在
*/
public boolean hHasKey(String key, String item){
return redisTemplate.opsForHash().hasKey(key, item);
}
/**
* hash递增 如果不存在,就会创建一个 并把新增后的值返回
* @param key 键
* @param item 项
* @param by 要增加几(大于0)
* @return
*/
public double hincr(String key, String item,double by){
return redisTemplate.opsForHash().increment(key, item, by);
}
/**
* hash递减
* @param key 键
* @param item 项
* @param by 要减少记(小于0)
* @return
*/
public double hdecr(String key, String item,double by){
return redisTemplate.opsForHash().increment(key, item,-by);
}
//============================set=============================
/**
* 根据key获取Set中的所有值
* @param key 键
* @return
*/
public Set<Object> sGet(String key){
try {
return redisTemplate.opsForSet().members(key);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 根据value从一个set中查询,是否存在
* @param key 键
* @param value 值
* @return true 存在 false不存在
*/
public boolean sHasKey(String key,Object value){
try {
return redisTemplate.opsForSet().isMember(key, value);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将数据放入set缓存
* @param key 键
* @param values 值 可以是多个
* @return 成功个数
*/
public long sSet(String key, Object...values) {
try {
return redisTemplate.opsForSet().add(key, values);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 将set数据放入缓存
* @param key 键
* @param time 时间(秒)
* @param values 值 可以是多个
* @return 成功个数
*/
public long sSetAndTime(String key,long time,Object...values) {
try {
Long count = redisTemplate.opsForSet().add(key, values);
if(time>0) expire(key, time);
return count;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 获取set缓存的长度
* @param key 键
* @return
*/
public long sGetSetSize(String key){
try {
return redisTemplate.opsForSet().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 移除值为value的
* @param key 键
* @param values 值 可以是多个
* @return 移除的个数
*/
public long setRemove(String key, Object ...values) {
try {
Long count = redisTemplate.opsForSet().remove(key, values);
return count;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
//===============================list=================================
/**
* 获取list缓存的内容
* @param key 键
* @param start 开始
* @param end 结束 0 到 -1代表所有值
* @return
*/
public List<Object> lGet(String key,long start, long end){
try {
return redisTemplate.opsForList().range(key, start, end);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 获取list缓存的长度
* @param key 键
* @return
*/
public long lGetListSize(String key){
try {
return redisTemplate.opsForList().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
/**
* 通过索引 获取list中的值
* @param key 键
* @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
* @return
*/
public Object lGetIndex(String key,long index){
try {
return redisTemplate.opsForList().index(key, index);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 将list放入缓存
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public boolean lSet(String key, Object value) {
try {
redisTemplate.opsForList().rightPush(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public boolean lSet(String key, Object value, long time) {
try {
redisTemplate.opsForList().rightPush(key, value);
if (time > 0) expire(key, time);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public boolean lSet(String key, List<Object> value) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 将list放入缓存
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public boolean lSet(String key, List<Object> value, long time) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
if (time > 0) expire(key, time);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 根据索引修改list中的某条数据
* @param key 键
* @param index 索引
* @param value 值
* @return
*/
public boolean lUpdateIndex(String key, long index,Object value) {
try {
redisTemplate.opsForList().set(key, index, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 移除N个值为value
* @param key 键
* @param count 移除多少个
* @param value 值
* @return 移除的个数
*/
public long lRemove(String key,long count,Object value) {
try {
Long remove = redisTemplate.opsForList().remove(key, count, value);
return remove;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
}
UserServiceimpl.java
/**
*
*/
package service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import bean.User;
import cn.qlq.util.RedisUtil;
import mapper.UserMapper;
@Transactional(rollbackFor=Exception.class)
@Service(value="userService")
public class UserServiceImpl implements UserService{
//用于手动添加缓存
@Autowired
private RedisUtil redisUtil = null;
@Autowired
private UserMapper userMapper = null;
//查询出来的时候添加单个缓存
@Cacheable(value="user",key="'user'+#id.toString()")
@Override
public User getUserById(int id) throws Exception {
//结果出来不用自己主动去添加,交给Spring去管理添加
return userMapper.getUserById(id);
}
//删除数据库的时候删除redis的缓存
@CacheEvict(value="user",key="'user'+#id.toString()")
@Override
public void deleteById(int id) throws Exception {
try {
userMapper.deleteById(id);
} catch (Exception ex) {
System.out.println("删除信息失败,强制回滚");
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
throw ex;
}
}
//添加缓存
@Cacheable(value="Alluser")
@Override
public List<User> getUserList() throws Exception {
return userMapper.getUserList();
}
//清除上面的缓存,同时手动的添加一个缓存看能否实现
//答案:不能清除上面的缓存,但是手动添加一个缓存实现了,后面就会知道原因了
@CacheEvict(value="Alluser")
@Override
public User addUser(int id) throws Exception {
redisUtil.set("mykey", "myvalue");
return userMapper.getUserById(id);
}
}
测试类
/**
*
*/
package test;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import bean.User;
import service.UserService;
/**
* @author 作者
* @data 2019年5月29日
*/
public class ServiceTest {
@Autowired
private ApplicationContext ctx = null;
@Autowired
private UserService userService = null;
//根据用户 的id
@Test
public void getUser() throws Exception {
ctx = new ClassPathXmlApplicationContext("spring/spring-service.xml");
userService = ctx.getBean(UserService.class);
int id =1;
User user = userService.getUserById(id);
System.out.println(user.toString());
}
//根据用户id删除缓存
@Test
public void delete() throws Exception {
ctx = new ClassPathXmlApplicationContext("spring/spring-service.xml");
userService = ctx.getBean(UserService.class);
int id =1;
userService.deleteById(id);
}
//查询所有对象
@Test
public void getUserList() throws Exception {
ctx = new ClassPathXmlApplicationContext("spring/spring-service.xml");
userService = ctx.getBean(UserService.class);
List<User> list=userService.getUserList();
for(int i=0;i<list.size();i++) {
System.out.println(list.get(i).toString());
}
}
//删除上面查询的所有对象的缓存,
//再自己手动添加一个缓存,
//再去数据库返回一个对象看看是否能自动添为缓存
@Test
public void deleteUser() throws Exception {
ctx = new ClassPathXmlApplicationContext("spring/spring-service.xml");
userService = ctx.getBean(UserService.class);
int id =2;
User user = userService.addUser(id);
System.out.println(user.toString());
}
}
类就差不多可,但是需要注意的一点是
存进缓存里的对象一定要有Serializable(序列化)接口,我们就可以直接存对象,有Spring容器把对象转成json字符串,不需要我们自己去转了
pom.xml必须有下面的包
<!-- json配置-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.0.pr3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.0.pr3</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.0.pr3</version>
</dependency>
<dependency>
配置文件
redis.properties
redis.host=127.0.0.1
redis.port=6379
redis.pass=
redis.dbIndex=0
redis.expiration=3000
redis.maxIdle=300
redis.maxActive=600
redis.maxWait=1000
redis.testOnBorrow=true
spring-redis.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:cache="http://www.springframework.org/schema/cache"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 连接池基本参数配置,类似数据库连接池 -->
<context:property-placeholder location="classpath:redis/redis.properties" ignore-unresolvable="true" />
<!-- 缓存注解开启 -->
<cache:annotation-driven cache-manager="redisCacheManager" key-generator="keyGenerator"/>
<!-- redis连接池 -->
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxTotal" value="${redis.maxActive}" />
<property name="maxIdle" value="${redis.maxIdle}" />
<property name="testOnBorrow" value="${redis.testOnBorrow}" />
</bean>
<!-- 连接池配置,类似数据库连接池 -->
<bean id="jedisConnectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="hostName" value="${redis.host}"></property>
<property name="port" value="${redis.port}"></property>
<!-- <property name="password" value="${redis.pass}"></property> -->
<property name="poolConfig" ref="poolConfig"></property>
</bean>
<!--redis操作模版,使用该对象可以操作redis -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" >
<property name="connectionFactory" ref="jedisConnectionFactory" />
<!--如果不配置Serializer,那么存储的时候缺省使用String,如果用User类型存储,那么会提示错误User can't cast to String!! -->
<property name="keySerializer" >
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
</property>
<property name="valueSerializer" >
<bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer" />
</property>
<property name="hashKeySerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
</property>
<property name="hashValueSerializer">
<bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer"/>
</property>
<!--开启事务 -->
<property name="enableTransactionSupport" value="true"></property>
</bean >
<!-- 配置RedisCacheManager -->
<bean id="redisCacheManager" class="org.springframework.data.redis.cache.RedisCacheManager">
<constructor-arg name="redisOperations" ref="redisTemplate" />
<property name="defaultExpiration" value="${redis.expiration}" />
</bean>
<!-- 下面就需要自己去写java类去实现 -->
<!-- 配置RedisCacheConfig -->
<bean id="redisCacheConfig" class="cn.qlq.util.RedisCacheConfig">
<constructor-arg ref="jedisConnectionFactory"/>
<constructor-arg ref="redisTemplate"/>
<constructor-arg ref="redisCacheManager"/>
</bean>
<!--自定义redis工具类,在需要缓存的地方注入此类 -->
<bean id="redisUtil" class="cn.qlq.util.RedisUtil">
<property name="redisTemplate" ref="redisTemplate" />
</bean>
<!-- 下面这个是整合Mybatis的二级缓存使用的 -->
<!-- <bean id="redisCacheTransfer" class="cn.qlq.jedis.RedisCacheTransfer">
<property name="jedisConnectionFactory" ref="jedisConnectionFactory" />
</bean>
-->
</beans>
sqlMapConfig.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- MyBatis的全局参数设置,基本用来进行MyBatis的优化处理 -->
<settings>
<!-- 开启二级缓存,这个需要开启 -->
<setting name="cacheEnabled" value="true"/>
<!-- 下面的是延迟加载 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 是否开启延迟加载 -->
<setting name="aggressiveLazyLoading" value="false"/>
<!-- 缓冲加载 -->
<setting name="cacheEnabled" value="true"/>
</settings>
<typeAliases>
<package name="bean.User"/>
</typeAliases>
</configuration>
spring-service
<import resource="spring-dao.xml"/>
<import resource="classpath*:/redis/spring-redis.xml"/>
加上上面两个,因为测试,所以需要,当生成项目时就用web.xml扫描了,就可以把上面的这两行删除
其他配置文件就是ssm的配置文件,基本上没什么需要修改的
测试结果
1、测试类的第一个测试:根据id查询对象
spring-data-redis在设置缓存的时候是将value的值加上~keys 存为一个zset,值就是每个具体的缓存的key,另一个具体的缓存的key注解里因为有key="‘user’+#id.toString()",所以存储在缓存里的key就是自己注解里的key,下面第三个测试将说明注解的key不写会怎么生成缓存的key
上面这个图说明了自己用注解存在缓存里的都有生命周期,这个可以修改,在redis.properties的redis.expiration配置上,单位是秒
建议缓存里的键的生命周期为6到9个小时,可以缓解缓存压力
2、测试类的第二个测试:删除缓存里的数据
3、测试类的第三个测试:获取数据库的所有对象,返回list集合(注解上专门不写key尝试)
上面图那一长串就是注解不写key,所以Spring容器自己生成的key,添加到缓存里,用的是RedisCacheConfig.java里的
上面重新书写了默认生成key的规则:类名-方法名-参数名。但是上图还是有区别的,因为我没有添加参数,所以最后是 - 结尾
这个也是,会自动添加生命周期,自己需要去修改生命周期,现在生命周期为3000s
4、测试类的第四个测试:测验删除第三个测试的缓存数据,并手动添加数据(用RedisUtil.java),
上图有了mykey,说明手动添加缓存没有任何问题,
但是第三个测试的那两个key没有删除,说明删除失败:其实从没有key时生成默认key的生成规则就知道**,最后一个测试生成的 key 和 第三个测试 默认生成的key根部就不可能相同,因为他们的方法名就不相同
总结:
如果在注解里注明了key的具体值,那么在缓存里会生成两个键,
- 一个是zset,里面存的是具体的key,命名规则是value+~keys
- 一个是String,里面存的是数据库返回的对象(集合/字符串),对象和集合需要转成json
例子:
@CacheEvict(value="user",key="'user'+#id.toString()")
如果不在注解里注明key的具体值,就是不写,那么Spring会根据KeyGenerator的generate(需要自己重写)的规则自己生成一个默认的key代替注解里没写的key执行生成上面那两个键
例子:
@Cacheable(value="Alluser")
最后说一下手动和注解实现redis当缓存的区别(个人感觉)
手动:会有小一些麻烦,在service层必须考虑redis的实现,很像顺序结构,到service 层 先考虑缓存,再考虑数据库,再考虑缓存(这三步都必须要考虑到,因为要时刻想到最坏的结果,缓存里没有)。比较自由,可以自己设定key的值,可以没有任何规则可言,自己设定生命周期(可以有的key就是很长,有的可以就是很短),还可以实现发布/订阅模式,实现消息队列,这些都可以用手动的方式解决
注解:比较简单,不过我感觉不如手动的功能多,如果用注解方式,redis就是用的它缓存的功能(没错,redis大部分情况下都是用它的缓存),用注解肯定要多生成一个zset,在逻辑上不用操心,只要在service的方法上写上注解,value,key…的该写的都写上,就没问题了,方法里的逻辑结构可以就不用考虑redis缓存的问题了,思维更加简单。
算法上有时间换空间或者空间换时间,根据不同的情况用不同的换法
redis实现缓存功能是灵活换简单,要想redis灵活运用就不要嫌麻烦,嫌麻烦用注解就不要嫌弃它不够灵活(死板)
再次强调,注解方式尽量自己一定要写上key,要不注解运用起来特别的难用
下面摘抄自
https://www.cnblogs.com/qlqwjy/p/8574121.html
@Cacheable 作用和配置方法
@Cacheable 的作用 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存
@Cacheable 主要的参数 | ||
---|---|---|
value | 缓存的名称,缓存中具体哪个数据库,在 spring 配置文件中定义,必须指定至少一个 | 例如:@Cacheable(value=”mycache”) 或者 @Cacheable(value={”cache1”,”cache2”} |
key | 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合,或者方法参数列表中的任意一个参数,或者字符串+参数组合 | 例如:@Cacheable(value=”testcache”,key=”#userName”) @Cacheable(value=”testcache”,key=” ‘字符串’+#userName”) |
condition | 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存 | 例如:@Cacheable(value=”testcache”,condition=”#userName.length()>2”) |
@CachePut 作用和配置方法
@CachePut 的作用 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存,和 @Cacheable不同的是,它每次都会触发真实方法的调用
@CachePut 主要的参数 | ||
---|---|---|
value | 缓存的名称,在 spring 配置文件中定义,必须指定至少一个 | 例如:@Cacheable(value=”mycache”) 或者 @Cacheable(value={”cache1”,”cache2”} |
key | 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 | 例如:@Cacheable(value=”testcache”,key=”#userName”) |
condition | 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存 | 例如:@Cacheable(value=”testcache”,condition=”#userName.length()>2”) |
@CacheEvict 作用和配置方法
@CachEvict 的作用 主要针对方法配置,能够根据一定的条件对缓存进行清空
@CacheEvict 主要的参数 | ||
---|---|---|
value | 缓存的名称,在 spring 配置文件中定义,必须指定至少一个 | 例如:@CachEvict(value=”mycache”) 或者 @CachEvict(value={”cache1”,”cache2”} |
key | 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合 | 例如:@CachEvict(value=”testcache”,key=”#userName”) |
condition | 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才清空缓存 | 例如:@CachEvict(value=”testcache”,condition=”#userName.length()>2”) |
allEntries | 是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存 | 例如:@CachEvict(value=”testcache”,allEntries=true) |
beforeInvocation | 是否在方法执行前就清空,缺省为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存 | 例如:@CachEvict(value=”testcache”,beforeInvocation=true) |
spEL表达式的使用方法:http://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/expressions.html
关于缓存注解的更详细的使用方法参考:http://www.cnblogs.com/qlqwjy/p/8559119.html