SpringBoot2.x 整合Redis实现缓存,自定义序列化和设置过期时间

SpringBoot2.x和1.x的区别很大,比如在整合 Redis 这一块,RedisCacheManager就有不同。

本文介绍 SpringBoot 2.0.5版本 整合 Redis。

 

一、基本配置

  1. pom.xml
  1. <!-- 里面依赖了spring-data-redis -->
  2.     <dependency>
  3.       <groupId>org.springframework.boot</groupId>
  4.       <artifactId>spring-boot-starter-data-redis</artifactId>
  5.     </dependency>

 

2.RedisConfig.java

  1. package com.liuyanzhao.sens.config;
  2. import lombok.extern.slf4j.Slf4j;
  3. import org.springframework.cache.annotation.EnableCaching;
  4. import org.springframework.context.annotation.Bean;
  5. import org.springframework.context.annotation.Configuration;
  6. import org.springframework.data.redis.cache.RedisCacheConfiguration;
  7. import org.springframework.data.redis.cache.RedisCacheManager;
  8. import org.springframework.data.redis.connection.RedisConnectionFactory;
  9. import org.springframework.data.redis.core.RedisTemplate;
  10. import org.springframework.data.redis.serializer.*;
  11. import java.time.Duration;
  12. /**
  13.  * @author 言曌
  14.  * @date 2018/5/21 上午10:02
  15.  */
  16. @Configuration
  17. @EnableCaching
  18. @Slf4j
  19. public class RedisConfig {
  20.     //过期时间1天
  21.     private Duration timeToLive = Duration.ofDays(1);
  22.     @Bean
  23.     public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
  24.         //默认1
  25.         RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
  26.                 .entryTtl(this.timeToLive)
  27.                 .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer()))
  28.                 .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(valueSerializer()))
  29.                 .disableCachingNullValues();
  30.         RedisCacheManager redisCacheManager = RedisCacheManager.builder(connectionFactory)
  31.                 .cacheDefaults(config)
  32.                 .transactionAware()
  33.                 .build();
  34.         log.debug("自定义RedisCacheManager加载完成");
  35.         return redisCacheManager;
  36.     }
  37.     @Bean(name = "redisTemplate")
  38.     public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
  39.         RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();
  40.         redisTemplate.setConnectionFactory(redisConnectionFactory);
  41.         redisTemplate.setKeySerializer(keySerializer());
  42.         redisTemplate.setHashKeySerializer(keySerializer());
  43.         redisTemplate.setValueSerializer(valueSerializer());
  44.         redisTemplate.setHashValueSerializer(valueSerializer());
  45.         log.debug("自定义RedisTemplate加载完成");
  46.         return redisTemplate;
  47.     }
  48.     private RedisSerializer<String> keySerializer() {
  49.         return new StringRedisSerializer();
  50.     }
  51.     private RedisSerializer<Object> valueSerializer() {
  52.         return new GenericJackson2JsonRedisSerializer();
  53.     }
  54. }

设置默认过期时间1天

GenericJackson2JsonRedisSerializer序列化value是采用json格式,里面有对象的class名称,便于反序列化。

 

二、@Cacheable和@CacheEvict 的使用

以友情链接的service实现为例

  1. package com.liuyanzhao.sens.service.impl;
  2. import com.liuyanzhao.sens.entity.Link;
  3. import com.liuyanzhao.sens.mapper.LinkMapper;
  4. import com.liuyanzhao.sens.service.LinkService;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.cache.annotation.CacheEvict;
  7. import org.springframework.cache.annotation.Cacheable;
  8. import org.springframework.stereotype.Service;
  9. import java.util.List;
  10. /**
  11.  * <pre>
  12.  *     友情链接业务逻辑实现类
  13.  * </pre>
  14.  *
  15.  * @author : saysky
  16.  * @date : 2017/11/14
  17.  */
  18. @Service
  19. public class LinkServiceImpl implements LinkService {
  20.     private static final String LINKS_CACHE_NAME = "links";
  21.     @Autowired(required = false)
  22.     private LinkMapper linkMapper;
  23.     @Override
  24.     @CacheEvict(value = LINKS_CACHE_NAME, allEntries = true, beforeInvocation = true)
  25.     public Link saveByLink(Link link) {
  26.         if (link != null && link.getLinkId() != null) {
  27.             linkMapper.updateById(link);
  28.         } else {
  29.             linkMapper.insert(link);
  30.         }
  31.         return link;
  32.     }
  33.     @Override
  34.     @CacheEvict(value = LINKS_CACHE_NAME, allEntries = true, beforeInvocation = true)
  35.     public void removeByLinkId(Long linkId) {
  36.         linkMapper.deleteById(linkId);
  37.     }
  38.     @Override
  39.     @Cacheable(value = LINKS_CACHE_NAME, key = "'links_all'")
  40.     public List<Link> findAllLinks() {
  41.         return linkMapper.findAll();
  42.     }
  43.     @Override
  44.     @Cacheable(value = LINKS_CACHE_NAME, key = "'links_id_'+#linkId", unless = "#result == null")
  45.     public Link findByLinkId(Long linkId) {
  46.         return linkMapper.selectById(linkId);
  47.     }
  48.     @Override
  49.     @Cacheable(value = LINKS_CACHE_NAME, key = "'links_count'")
  50.     public Integer getCount() {
  51.         return linkMapper.selectCount(null);
  52.     }
  53. }

除了 @Cacheable、@CacheEvict之外,还有@CachePut,一般不用

查询一律用 @Cacheable,先从 Redis 查有没有这个 key,如果没有则执行方法里的代码,从数据库查询,并将结果存到 Redis 中。

@CacheEvict 可以指定删除某个 key,也可以删除 value 集合的所有 key。

 

三、Redis工具类

  1. package com.liuyanzhao.sens.utils;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. import org.springframework.data.redis.core.StringRedisTemplate;
  4. import org.springframework.stereotype.Component;
  5. import java.util.Map;
  6. import java.util.Set;
  7. import java.util.concurrent.TimeUnit;
  8. /**
  9.  * @author 言曌
  10.  * @date 2018/12/16 下午6:57
  11.  */
  12. @Component
  13. public class RedisUtil {
  14.     @Autowired
  15.     private StringRedisTemplate redisTemplate;
  16.     // Key(键),简单的key-value操作
  17.     /**
  18.      * 实现命令:TTL key,以秒为单位,返回给定 key的剩余生存时间(TTL, time to live)。
  19.      *
  20.      * @param key
  21.      * @return
  22.      */
  23.     public long ttl(String key) {
  24.         return redisTemplate.getExpire(key);
  25.     }
  26.     /**
  27.      * 实现命令:expire 设置过期时间,单位秒
  28.      *
  29.      * @param key
  30.      * @return
  31.      */
  32.     public void expire(String key, long timeout) {
  33.         redisTemplate.expire(key, timeout, TimeUnit.SECONDS);
  34.     }
  35.     /**
  36.      * 实现命令:INCR key,增加key一次
  37.      *
  38.      * @param key
  39.      * @return
  40.      */
  41.     public long incr(String key, long delta) {
  42.         return redisTemplate.opsForValue().increment(key, delta);
  43.     }
  44.     /**
  45.      * 实现命令: key,减少key一次
  46.      *
  47.      * @param key
  48.      * @return
  49.      */
  50.     public long decr(String key, long delta) {
  51.         if(delta<0){
  52. //            throw new RuntimeException("递减因子必须大于0");
  53.             del(key);
  54.             return 0;
  55.         }
  56.         return redisTemplate.opsForValue().increment(key, -delta);
  57.     }
  58.     /**
  59.      * 实现命令:KEYS pattern,查找所有符合给定模式 pattern的 key
  60.      */
  61.     public Set<String> keys(String pattern) {
  62.         return redisTemplate.keys(pattern);
  63.     }
  64.     /**
  65.      * 实现命令:DEL key,删除一个key
  66.      *
  67.      * @param key
  68.      */
  69.     public void del(String key) {
  70.         redisTemplate.delete(key);
  71.     }
  72.     // String(字符串)
  73.     /**
  74.      * 实现命令:SET key value,设置一个key-value(将字符串值 value关联到 key)
  75.      *
  76.      * @param key
  77.      * @param value
  78.      */
  79.     public void set(String key, String value) {
  80.         redisTemplate.opsForValue().set(key, value);
  81.     }
  82.     /**
  83.      * 实现命令:SET key value EX seconds,设置key-value和超时时间(秒)
  84.      *
  85.      * @param key
  86.      * @param value
  87.      * @param timeout (以秒为单位)
  88.      */
  89.     public void set(String key, String value, long timeout) {
  90.         redisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS);
  91.     }
  92.     /**
  93.      * 实现命令:GET key,返回 key所关联的字符串值。
  94.      *
  95.      * @param key
  96.      * @return value
  97.      */
  98.     public String get(String key) {
  99.         return (String) redisTemplate.opsForValue().get(key);
  100.     }
  101.     // Hash(哈希表)
  102.     /**
  103.      * 实现命令:HSET key field value,将哈希表 key中的域 field的值设为 value
  104.      *
  105.      * @param key
  106.      * @param field
  107.      * @param value
  108.      */
  109.     public void hset(String key, String field, Object value) {
  110.         redisTemplate.opsForHash().put(key, field, value);
  111.     }
  112.     /**
  113.      * 实现命令:HGET key field,返回哈希表 key中给定域 field的值
  114.      *
  115.      * @param key
  116.      * @param field
  117.      * @return
  118.      */
  119.     public String hget(String key, String field) {
  120.         return (String) redisTemplate.opsForHash().get(key, field);
  121.     }
  122.     /**
  123.      * 实现命令:HDEL key field [field ...],删除哈希表 key 中的一个或多个指定域,不存在的域将被忽略。
  124.      *
  125.      * @param key
  126.      * @param fields
  127.      */
  128.     public void hdel(String key, Object... fields) {
  129.         redisTemplate.opsForHash().delete(key, fields);
  130.     }
  131.     /**
  132.      * 实现命令:HGETALL key,返回哈希表 key中,所有的域和值。
  133.      *
  134.      * @param key
  135.      * @return
  136.      */
  137.     public Map<Object, Object> hgetall(String key) {
  138.         return redisTemplate.opsForHash().entries(key);
  139.     }
  140.     // List(列表)
  141.     /**
  142.      * 实现命令:LPUSH key value,将一个值 value插入到列表 key的表头
  143.      *
  144.      * @param key
  145.      * @param value
  146.      * @return 执行 LPUSH命令后,列表的长度。
  147.      */
  148.     public long lpush(String key, String value) {
  149.         return redisTemplate.opsForList().leftPush(key, value);
  150.     }
  151.     /**
  152.      * 实现命令:LPOP key,移除并返回列表 key的头元素。
  153.      *
  154.      * @param key
  155.      * @return 列表key的头元素。
  156.      */
  157.     public String lpop(String key) {
  158.         return (String) redisTemplate.opsForList().leftPop(key);
  159.     }
  160.     /**
  161.      * 实现命令:RPUSH key value,将一个值 value插入到列表 key的表尾(最右边)。
  162.      *
  163.      * @param key
  164.      * @param value
  165.      * @return 执行 LPUSH命令后,列表的长度。
  166.      */
  167.     public long rpush(String key, String value) {
  168.         return redisTemplate.opsForList().rightPush(key, value);
  169.     }
  170. }

使用的时候只需要注入 RedisUtil,然后就可以简单操作 Redis

 

最终效果

SpringBoot2.x 整合Redis实现缓存,自定义序列化和设置过期时间

 

  • 微信
  • 交流学习,有偿服务
  • weinxin
  • 博客/Java交流群
  • 资源分享,问题解决,技术交流。群号:590480292
  • weinxin
言曌

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: