前言

最近在做智能家居平台,考虑到家居的控制需要快速的响应于是打算使用redis缓存。一方面减少数据库压力另一方面又能提高响应速度。项目中使用的技术栈基本上都是大家熟悉的springboot全家桶,在springboot2.x以后操作redis的客户端推荐使用lettuce(生菜)取代jedis。

jedis的劣势主要在于直连redis,又无法做到弹性收缩。

一、配置文件

application.yml文件中的内容

  1. spring:
  2. application:
  3. name: simple-lettuce
  4. cache:
  5. type: redis
  6. redis:
  7. # 缓存超时时间ms
  8. time-to-live:
  9. # 是否缓存空值
  10. cache-null-values: true
  11. redis:
  12. host: 127.0.0.1
  13. port:
  14. password:
  15. # 连接超时时间(毫秒)
  16. timeout:
  17. # Redis默认情况下有16个分片,这里配置具体使用的分片,默认是0
  18. database:
  19. # spring2.x redis client 采用了lettuce(生菜),放弃使用jedis
  20. lettuce:
  21. # 关闭超时时间
  22. shutdown-timeout:
  23. pool:
  24. # 连接池最大连接数(使用负值表示没有限制) 默认
  25. max-active:
  26. # 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -
  27. max-wait: -
  28. # 连接池中的最大空闲连接 默认
  29. max-idle:
  30. # 连接池中的最小空闲连接 默认
  31. min-idle:

说明:

  • spring.cache.type: redis

已经表明使用项目采用redis做为缓存方式。

  • spring.cache.redis.cache-null-values: true

表示是否缓存空值,一般情况下是允许的。因为这涉及到缓存的三大问题:缓存穿透、缓存雪崩、缓存击穿。

如果设置false即不允许缓存空值,这样会导致很多请求数据库没有的数据时,不会缓存到redis导致每次都会请求到数据库。这种情况即:缓存穿透。

具体想初步了解这些概念可以参考文章:缓存三大问题及解决方案!

二、config配置类

  1. @Configuration
  2. @EnableCaching
  3. public class RedisTemplateConfig extends CachingConfigurerSupport {
  4.  
  5. private static Map<String, RedisCacheConfiguration> cacheMap = Maps.newHashMap();
  6.  
  7. @Bean(name = "stringRedisTemplate")
  8. @ConditionalOnMissingBean(name = "stringRedisTemplate") //表示:如果容器已经有redisTemplate bean就不再注入
  9. public StringRedisTemplate stringRedisTemplate(LettuceConnectionFactory redisConnectionFactory) {return new StringRedisTemplate(redisConnectionFactory);
  10. }
  11.  
  12. @Bean(name = "redisTemplate")
  13. @ConditionalOnMissingBean(name = "redisTemplate")
  14. public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
  15. System.out.println("RedisTemplateConfig.RedisTemplate");
  16. RedisTemplate<String, Object> template = new RedisTemplate<>();
  17. // key的序列化采用StringRedisSerializer
  18. template.setKeySerializer(keySerializer());
  19. template.setHashKeySerializer(keySerializer());
  20. // value值的序列化采用fastJsonRedisSerializer
  21. template.setValueSerializer(valueSerializer()); //使用fastjson序列化
  22. template.setHashValueSerializer(valueSerializer()); //使用fastjson序列化
  23. template.setConnectionFactory(lettuceConnectionFactory);
  24. return template;
  25. }
  26.  
  27. /**
  28. * 添加自定义缓存异常处理
  29. * 当缓存读写异常时,忽略异常
  30. * 参考:https://blog.csdn.net/sz85850597/article/details/89301331
  31. */
  32. @Override
  33. public CacheErrorHandler errorHandler() {
  34. return new IgnoreCacheErrorHandler();
  35. }
  36.  
  37. @SuppressWarnings("Duplicates")
  38. @Bean
  39. @Primary//当有多个管理器的时候,必须使用该注解在一个管理器上注释:表示该管理器为默认的管理器
  40. public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
  41. // 默认配置
  42. RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig()
  43. .serializeKeysWith(keyPair())
  44. .serializeValuesWith(valuePair())
  45. .entryTtl(Duration.ofSeconds(DEFAULT_TTL_SECS)) //设置过期时间
  46. .disableCachingNullValues();
  47.  
  48. // 其它配置
  49. for(MyCaches cache : MyCaches.values()) {
  50. cacheMap.put(cache.name(),
  51. RedisCacheConfiguration.defaultCacheConfig()
  52. .serializeKeysWith(keyPair())
  53. .serializeValuesWith(valuePair())
  54. .entryTtl(cache.getTtl())
  55. // .disableCachingNullValues() // 表示不允许缓存空值
  56. .disableKeyPrefix() // 不使用默认前缀
  57. // .prefixKeysWith("mytest") // 添加自定义前缀
  58. );
  59. }
  60.  
  61. /** 遍历MyCaches添加缓存配置*/
  62. RedisCacheManager cacheManager = RedisCacheManager.builder(
  63. RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory)
  64. )
  65. .cacheDefaults(defaultCacheConfig)
  66. .withInitialCacheConfigurations(cacheMap)
  67. .transactionAware()
  68. .build();
  69.  
  70. ParserConfig.getGlobalInstance().addAccept("mypackage.db.entity.");
  71. return cacheManager;
  72. }
  73.  
  74. /**
  75. * key序列化方式
  76. * @return
  77. */
  78. private RedisSerializationContext.SerializationPair<String> keyPair() {
  79. RedisSerializationContext.SerializationPair<String> keyPair =
  80. RedisSerializationContext.SerializationPair.fromSerializer(keySerializer());
  81. return keyPair;
  82. }
  83.  
  84. private RedisSerializer<String> keySerializer() {
  85. return new StringRedisSerializer();
  86. }
  87.  
  88. /**
  89. * value序列化方式
  90. * @return
  91. */
  92. private RedisSerializationContext.SerializationPair<Object> valuePair() {
  93. RedisSerializationContext.SerializationPair<Object> valuePair =
  94. RedisSerializationContext.SerializationPair.fromSerializer(valueSerializer());
  95. return valuePair;
  96. }
  97.  
  98. /**
  99. * 使用fastjson序列化
  100. * @return
  101. */
  102. private RedisSerializer<Object> valueSerializer() {
  103. MyFastJsonRedisSerializer<Object> fastJsonRedisSerializer = new MyFastJsonRedisSerializer<>(Object.class);
  104. return fastJsonRedisSerializer;
  105. }
  106.  
  107. @Getter
  108. private enum MyCaches {
  109. defaultCache(Duration.ofDays(1)),
  110. MyCaches(Duration.ofMinutes(10));
  111.  
  112. MyCaches(Duration ttl) {
  113. this.ttl = ttl;
  114. }
  115. /** 失效时间 */
  116. private Duration ttl = Duration.ofHours(1);
  117. }
  118. }

 说明

1. 类上的注解@EnableCaching

表明开启缓存功能。

2. extends CachingConfigurerSupport

这个类就很丰富了,其实如果没有什么特别操作也可以不用继承这个类。

这个类可以支持动态选择缓存方式,比如项目中不止一种缓存方案,有可能有ehcache那么可以自定义在什么情况下使用redis使用情况下使用ehcache。还有一些有关异常的处理。我也不是很懂具体可以参考:

3. StringRedisTemplate和RedisTemplate的使用

(1)两者的主要差别是:如果你只想缓存简单的字符串选择StringRedisTemplate是一个明智的举措。如果想使用redis缓存一些对象数据肯定是要选择RedisTemplate。
 
(2)RedisTemplate需要注意一点就是要怎么选择序列化工具。默认使用jdk的序列化缓存数据后即value值是无法直接阅读的而存的二进制数据。
通常我们会选择jackson或者fastjson来序列化对象,把对象转换成json格式。两者序列化对象后都会在头部加上一个对象类路径如:@type com.mypackage.entity.User。这个也算是一种安全策略。
比如使用fastjosn就会在cacheManager中指定序列化对象的包所在位置白名单:ParserConfig.getGlobalInstance().addAccept("mypackage.db.entity.");
fastjson官方说明:https://github.com/alibaba/fastjson/wiki/enable_autotype
 
(3)还有需要注意如果value是string类型。RedisTemplate会在字符串外围再加一对双引号,如""abc""。如果使用StringRedisTemplate读取则能得到abc,但是我在项目使用Jedis读取就成了"abc"这就导致这些字符串无法被反序列化。
 
(4)StringRedisTemplate和RedisTemplate两者数据是相互隔离的,如果使用StringRedisTemplate存入的数据使用RedisTemplate是无法读取、删除的。
 
 

三、缓存注解使用

@Cacheable 使用在查询方法上

@CachePut 使用在更新、保存方法上

@CacheEvict 使用在删除方法上

需要注意的是@Cacheable、@CachePut方法一定要有返回被缓存对象。因为注解使用的AOP切面如果没有返回值表示缓存对象为空值。

@CacheConfig注解在类上,可以选择使用哪个缓存、缓存管理器、Key生成器

好了以上就是最近在项目中的一些知识点总结,如果以后使用缓存有新的体会我会同步更新的。

springboot整合redis缓存一些知识点的更多相关文章

  1. SpringBoot 整合 Redis缓存

    在我们的日常项目开发过程中缓存是无处不在的,因为它可以极大的提高系统的访问速度,关于缓存的框架也种类繁多,今天主要介绍的是使用现在非常流行的NoSQL数据库(Redis)来实现我们的缓存需求. Spr ...

  2. springboot整合redis缓存

    使用springBoot添加redis缓存需要在POM文件里引入 org.springframework.bootspring-boot-starter-cacheorg.springframewor ...

  3. SpringBoot整合redis缓存(一)

    准备工作 1.Linux系统 2.安装redis(也可以安装docker,然后再docker中装redis,本文章就直接用Linux安装redis做演示) redis下载地址: 修改redis,开启远 ...

  4. SpringBoot缓存管理(二) 整合Redis缓存实现

    SpringBoot支持的缓存组件 在SpringBoot中,数据的缓存管理存储依赖于Spring框架中cache相关的org.springframework.cache.Cache和org.spri ...

  5. SpringBoot入门系列(七)Spring Boot整合Redis缓存

    前面介绍了Spring Boot 中的整合Mybatis并实现增删改查,.不清楚的朋友可以看看之前的文章:https://www.cnblogs.com/zhangweizhong/category/ ...

  6. springBoot整合redis(作缓存)

    springBoot整合Redis 1,配置Redis配置类 package org.redislearn.configuration; import java.lang.reflect.Method ...

  7. SpringBoot整合Redis、mybatis实战,封装RedisUtils工具类,redis缓存mybatis数据 附源码

    创建SpringBoot项目 在线创建方式 网址:https://start.spring.io/ 然后创建Controller.Mapper.Service包 SpringBoot整合Redis 引 ...

  8. Redis-基本概念、java操作redis、springboot整合redis,分布式缓存,分布式session管理等

    NoSQL的引言 Redis数据库相关指令 Redis持久化相关机制 SpringBoot操作Redis Redis分布式缓存实现 Resis中主从复制架构和哨兵机制 Redis集群搭建 Redis实 ...

  9. SpringBoot整合Redis、ApachSolr和SpringSession

    SpringBoot整合Redis.ApachSolr和SpringSession 一.简介 SpringBoot自从问世以来,以其方便的配置受到了广大开发者的青睐.它提供了各种starter简化很多 ...

随机推荐

  1. 快速识别Hash加密方式hashid

    快速识别Hash加密方式hashid hashid工具是用来识别不同类型的散列加密,进而判断哈希算法的类型.该工具的而语法格式如下所示: hashid [option] INPUT 其中,option ...

  2. 字典树(查找树) leetcode 208. Implement Trie (Prefix Tree) 、211. Add and Search Word - Data structure design

    字典树(查找树) 26个分支作用:检测字符串是否在这个字典里面插入.查找 字典树与哈希表的对比:时间复杂度:以字符来看:O(N).O(N) 以字符串来看:O(1).O(1)空间复杂度:字典树远远小于哈 ...

  3. 一、postman简介

    一.场景 1.开发接口的时候需要快速的调用接口,以便调试 2.测试的时候需要非常方便的调用接口,通过不同的参数去测试接口的输出 3.这些接口调用是需要保存下来的反复运行的 4.在运行过程中如果有断言( ...

  4. Python3基础 交换两个变量的值

             Python : 3.7.3          OS : Ubuntu 18.04.2 LTS         IDE : pycharm-community-2019.1.3    ...

  5. MongoDB数据表添加字段

    db.tshare_a.insert( { "_id" : ObjectId("57172b0f657f8bbb34d70147"), "picUrl ...

  6. Flutter Navigator&Router(导航与路由)

    参考地址:https://www.jianshu.com/p/b9d6ec92926f 在我们Flutter中,页面之间的跳转与数据传递使用的是Navigator.push和Navigator.pop ...

  7. Spring cloud微服务安全实战-3-8API安全机制之Https

    Https访问 1.验证双方的身份. 2.一旦建立连接,对数据进行封装加密 这里先生成一个自己自签的证书,不是第三方颁发的,第三方颁发的要花钱. 第二是做一些配置,让程序支持https 安装了java ...

  8. python中异常处理之esle,except,else

    异常是指程序中的例外,违例情况.异常机制是指程序出现错误后,程序的处理方法.当出现错误后,程序的执行流程发生改变,程序的控制权转移到异常处理. python中使用try...except语句捕获异常, ...

  9. Python - Django - 模板语言之 Filters(过滤器)

    通过管道符 "|" 来使用过滤器,{{ value|过滤器:参数 }} Django 的模板语言中提供了六十个左右的内置过滤器 urls.py: from django.conf. ...

  10. 如何关闭phpstrom的更新提醒?

    在file-----setting-------搜索updates 把检测版本更新的对勾点掉就可以了, 自己破解后的版本就别更新了,更新后就不能再用了,目前用代理服务器激活可以用版本3.3,升级到3. ...