首先了解两个知识点
一.RedisTemplate和StringRedisTemplate区别
在java中操作redis有很多方式,其中spring提供了其擅长的模板管理RedisTemplate和StringRedisTemplate两个类操作redis,他们两个的区别在于序列化的方式不一样
RedisTemplate使用的序列化方式在操作数据的时候,比如存入数据,会把数据先序列化成字节数组然后存入redis中,如 \xA0\sxa0\oE4
StringRedisTemplate 使用的序列化方式存入redis中的则是正常的String类型的字符类型
并且两者的数据不是共通的
另附RedisTemplate操作链接:https://www.jianshu.com/p/7bf5dc61ca06
二.注解@EnableCaching
Spring缓存注解@Cacheable、@CacheEvict、@CachePut使用
从3.1开始,Spring引入了对Cache的支持。其使用方法和原理都类似于Spring对事务管理的支持。Spring Cache是作用在方法上的,其核心思想是这样的:当我们在 调用一个缓存方法时会把该方法参数和返回结果作为一个键值对存放在缓存中,等到下次利用同样的参数来调用该方法时将不再执行该方法,而是直接从缓存中获取结 果进行返回。所以在使用Spring Cache的时候我们要保证我们缓存的方法对于相同的方法参数要有相同的返回结果。
使用Spring Cache需要我们做两方面的事:
和Spring对事务管理的支持一样,Spring对Cache的支持也有基于注解和基于XML配置两种方式。下面我们先来看看基于注解的方式。
1 基于注解的支持
Spring为我们提供了几个注解来支持Spring Cache。其核心主要是@Cacheable和@CacheEvict。使用@Cacheable标记的方法在执行后Spring Cache将缓存其返回结果,而使用@CacheEvict标记的方法会在方法执行前或者执行后移除Spring Cache中的某些元素。下面我们将来详细介绍一下Spring基于注解对Cache的支持所提供的几个注解。
1.1 @Cacheable
@Cacheable可以标记在一个方法上,也可以标记在一个类上。当标记在一个方法上时表示该方法是支持缓存的,当标记在一个类上时则表示该类所有的方法都是支持缓存的。对于一个支持缓存的方法,Spring会在其被调用后将其返回值缓存起来,以保证下次利用同样的参数来执行该方法时可以直接从缓存中获取结果,而不需要再次执行该方法。Spring在缓存方法的返回值时是以键值对进行缓存的,值就是方法的返回结果,至于键的话,Spring又支持两种策略,默认策略和自定义策略,这个稍后会进行说明。需要注意的是当一个支持缓存的方法在对象内部被调用时是不会触发缓存功能的。@Cacheable可以指定三个属性,value、key和condition。
1.2 @CachePut
在支持Spring Cache的环境下,对于使用@Cacheable标注的方法,Spring在每次执行前都会检查Cache中是否存在相同key的缓存元素,如果存在就不再执行该方法,而是直接从缓存中获取结果进行返回,否则才会执行并将返回结果存入指定的缓存中。@CachePut也可以声明一个方法支持缓存功能。与@Cacheable不同的是使用@CachePut标注的方法在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式存入指定的缓存中。
@CachePut也可以标注在类上和方法上。使用@CachePut时我们可以指定的属性跟@Cacheable是一样的。
@CachePut(“users”)//每次都会执行方法,并将结果存入指定的缓存中 public User find(Integer id) { returnnull; }
1.3 @CacheEvict
@CacheEvict是用来标注在需要清除缓存元素的方法或类上的。当标记在一个类上时表示其中所有的方法的执行都会触发缓存的清除操作。@CacheEvict可以指定的属性有value、key、condition、allEntries和beforeInvocation。其中value、key和condition的语义与@Cacheable对应的属性类似。即value表示清除操作是发生在哪些Cache上的(对应Cache的名称);key表示需要清除的是哪个key,如未指定则会使用默认策略生成的key;condition表示清除操作发生的条件。下面我们来介绍一下新出现的两个属性allEntries和beforeInvocation。
1.4 @Caching
@Caching注解可以让我们在一个方法或者类上同时指定多个Spring Cache相关的注解。其拥有三个属性:cacheable、put和evict,分别用于指定@Cacheable、@CachePut和@CacheEvict。
@Caching(cacheable = @Cacheable(“users”), evict = { @CacheEvict(“cache2”), @CacheEvict(value = "cache3", allEntries = true) }) public User find(Integer id) { returnnull; }
@CacheEvict 应该和 @Cacheable 搭配使用
@CacheEvict(cacheNames = CacheModule.APP, key = "T(com.gws.base.CachePrefix).APP.concat(T(String).valueOf(#app.getAppId()))") @Override public App updateApp(App app) { if (null == app){ return null; } appMaster.updateById(app,app.getAppId(),"appId","appName","appVersion","osType","icon1","icon2","pkgPath","appAbstract"); return app; }
@Cacheable(cacheNames = CacheModule.APP, key = "T(com.gws.base.CachePrefix).APP.concat(T(String).valueOf(#appId))") @Override public App getApp(Long appId) { if (null == appId) { return null; } return appSlave.findOne(appId); }
执行流程:
1.当执行获取的方法的时候,会将缓存放到数据库
2.当执行更改的时候,会清理掉数据库的缓存
Springboot整合Redis,并使用Redis做为缓存
1.导入redis依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-redis</artifactId> <version>1.3.8.RELEASE</version> </dependency>
2.配置RedisConfig
@Configuration @EnableCaching @PropertySource(value = "classpath:/redis.properties") public class RedisConfig extends CachingConfigurerSupport { private Logger logger = LoggerFactory.getLogger(RedisConfig.class); @Value("${spring.redis.host}") private String host; @Value("${spring.redis.port}") private int port; @Value("${spring.redis.timeout}") private int timeout; @Value("${spring.redis.pool.max-active}") private int maxActive; //生成key的策略 @Bean public KeyGenerator wiselyKeyGenerator() { return new KeyGenerator() { @Override public Object generate(Object target, Method method, Object... objects) { StringBuilder sb = new StringBuilder(); sb.append(target.getClass().getName()) .append(method.getName()); for (Object obj : objects) { sb.append(obj.toString()); } logger.info("id:" + sb.toString()); return sb.toString(); } }; } //redis连接池 @Bean public JedisPoolConfig jedisPoolConfig() { JedisPoolConfig jedisPoolConfig = new JedisPoolConfig(); jedisPoolConfig.setBlockWhenExhausted(true); jedisPoolConfig.setTestOnBorrow(true); jedisPoolConfig.setMaxTotal(maxActive); return jedisPoolConfig; } //配置连接工厂 @Bean public JedisConnectionFactory redisConnectionFactory(JedisPoolConfig jedisPoolConfig) { JedisConnectionFactory factory = new JedisConnectionFactory(); factory.setHostName(host); factory.setPort(port); factory.setTimeout(timeout); factory.setPoolConfig(jedisPoolConfig); return factory; } // 选择redis作为默认缓存工具 @Bean public CacheManager cacheManager(RedisConnectionFactory factory) { return RedisCacheManager .builder(factory) .cacheDefaults(RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofMinutes(5))) .transactionAware() .build(); } //配置redisTemplate @Bean public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory redisConnectionFactory) { Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper om = new ObjectMapper(); om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jackson2JsonRedisSerializer.setObjectMapper(om); StringRedisTemplate template = new StringRedisTemplate(redisConnectionFactory); //修改序列化,则序列化的对象就不需要实现Serializer接口 template.setKeySerializer(jackson2JsonRedisSerializer); template.setValueSerializer(jackson2JsonRedisSerializer); template.setHashKeySerializer(jackson2JsonRedisSerializer); template.setHashValueSerializer(jackson2JsonRedisSerializer); template.afterPropertiesSet(); return template; } }
3.抽取RedisUtil类
@Component public class RedisUtil { @Autowired private RedisTemplate redisTemplate; /** * 写入缓存 * * @param key * @param value * @return */ public boolean set(String key, Object value) { boolean result = false; try { redisTemplate.opsForValue().set(key, value); return true; } catch (Exception e) { e.printStackTrace(); } return result; } /** * 写入缓存,写入超时时间 * * @param key * @param value * @param timeout 时长 * @param timeUnit 时长单位 * @return */ public boolean set(String key, Object value, long timeout, TimeUnit timeUnit) { boolean result = false; try { redisTemplate.opsForValue().set(key, value, timeout, timeUnit); return true; } catch (Exception e) { e.printStackTrace(); } return result; } /** * 批量删除对应的value * * @param key */ public void remove(String... key) { for (String k:key){ remove(k); } } /** 删除对应的value * @param key */ public void remove(String key) { if (exists(key)){ redisTemplate.delete(key); } } /**判断是否存在key * @param key * @return */ public boolean exists(String key){ return redisTemplate.hasKey(key); } /**读取缓存 * @param key * @return */ public Object get(String key){ Object result=null; result= redisTemplate.opsForValue().get(key); return result; } /**添加hash值 * @param key * @param hashKey * @param value */ public void hmSet(String key,Object hashKey,Object value){ redisTemplate.opsForHash().put(key,hashKey,value); } /** * 哈希获取数据 * @param key * @param hashKey * @return */ public Object hmGet(String key, Object hashKey){ HashOperations<String, Object, Object> hash = redisTemplate.opsForHash(); return hash.get(key,hashKey); } /** * 列表添加 * @param k * @param v */ public void lPush(String k,Object v){ ListOperations<String, Object> list = redisTemplate.opsForList(); list.rightPush(k,v); } /** * 列表获取 * @param k * @param l * @param l1 * @return */ public List<Object> lRange(String k, long l, long l1){ ListOperations<String, Object> list = redisTemplate.opsForList(); return list.range(k,l,l1); } /** * 集合添加 * @param key * @param value */ public void add(String key,Object value){ SetOperations<String, Object> set = redisTemplate.opsForSet(); set.add(key,value); } /** * 集合获取 * @param key * @return */ public Set<Object> setMembers(String key){ SetOperations<String, Object> set = redisTemplate.opsForSet(); return set.members(key); } /** * 有序集合添加 * @param key * @param value * @param scoure */ public void zAdd(String key,Object value,double scoure){ ZSetOperations<String, Object> zset = redisTemplate.opsForZSet(); zset.add(key,value,scoure); } /** * 有序集合获取 * @param key * @param scoure * @param scoure1 * @return */ public Set<Object> rangeByScore(String key,double scoure,double scoure1){ ZSetOperations<String, Object> zset = redisTemplate.opsForZSet(); return zset.rangeByScore(key, scoure, scoure1); } }
4.在项目中使用
@Controller @RequestMapping("/twjd") public class LogController { @Autowired private LogService logService; @Autowired private RedisUtil redisUtil; private Logger logger = LoggerFactory.getLogger(LogController.class); /** * 增加用户 * * @param sysusers * @return */ @RequestMapping(value = "/addUser", method = RequestMethod.POST) @ResponseBody public String addUser(Sysuser sysusers) { //使用redis if (redisUtil.exists(sysusers.getName())) { redisUtil.set(sysusers.getName(), sysusers); } return "增加成功"; } /** * 获取用户 * * @param sysusers * @return */ @RequestMapping(value = "/getUser") @ResponseBody @Cacheable(value ="userCache",key ="#sysusers.name") //使用缓存注解,如果传入的参数相同,则命中缓存,直接返回,#sysusers.name是获取到传入参数的name public String getUser(Sysuser sysusers) { //代理的情况下需要用接口接收 LogService bind = (LogService) new CacheLockDynaProxy().bind(new logServiceImpl()); bind.getUser("1"); Sysuser user = null; if (!StringEmpty.IsEmpty(sysusers.getName())) { user = logService.getUser(sysusers.getName()); logger.info("从数据库查询"); new HashMap<>(); } return JSON.toJSON(user).toString(); } }
原文:https://www.cnblogs.com/yq-cc/p/11330953.html