Spring+Mybatis+redis整合(用注解的方式)
手动的操作缓存自己解决了,原本想着以后就用手动的方式,可是不研究研究注解感觉自己错过了什么,现在弄完了,感觉真是简单,比手动的方式简单太多了,可能是我直接用的别人的工具类可能简单,如果手动的方式中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=================== 1b5d8 ========== /** * 根据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
- SpringBoot + mybatis +redis 注解的方式
- Spring与Mybatis基于注解整合Redis的方法
- Spring AOP如何整合redis(注解方式)实现缓存统一管理详解
- SpringMVC+MyBatis整合(注解方式)
- springMVC+hibernate+jdbc+mybatis整合 支持全注解方式 支持全配置方式
- spring + spring mvc + mybatis 整合项目 全注解方式
- Spring整合Mybatis(注解方式完整过程,摒弃MyBatis配置文件)
- Spring Boot系列之六 以注解方式整合MyBatis
- Spring+SpringMVC+mybatis+easyui整合实例(二)注解方式的mybatis的使用
- Spring AOP整合redis(注解方式) 实现缓存统一管理
- Redis详解 - SpringBoot整合Redis,RedisTemplate和注解两种方式的使用
- MyBatis学习(二):与Spring整合(非注解方式配置MyBatis)
- Spring与Mybatis基于注解整合Redis的方法
- Spring + Spring MVC + Mybatis + Swagger + javaConfig 整合项目 全注解方式
- Spring+SpringMVC+mybatis+easyui整合-----注解方式的mybatis的使用
- Spring整合mybatis的配置文件(非注解方式,无springMVC)
- mybatis和spring整合的几种方式及使用注解简化sql(不使用xml方式写sql)
- spring+sprinmvc+mybatis基本整合(二)--基于spring注解mybais非注解非Mapper接口方式
- Spring整合Redis用作缓存-注解方式