Java SpringCache+Redis缓存数据详解

目录
  • 前言
  • 一、什么是SpringCache
  • 二、项目集成Spring Cache + Redis
    • 1、配置方式
  • 三、使用Spring Cache
  • 四、SpringCache原理与不足
    • 1、读模式
    • 2、写模式:(缓存与数据库一致)
  • 五、总结

前言

这几天学习谷粒商城又再次的回顾了一次SpringCache,之前在学习谷粒学院的时候其实已经学习了一次了!!!

这里就对自己学过来的内容进行一次的总结和归纳!!!

一、什么是SpringCache

  • Spring Cache 是一个非常优秀的缓存组件。自Spring 3.1起,提供了类似于@Transactional注解事务的注解Cache支持,且提供了Cache抽象,方便切换各种底层Cache(如:redis)
  • 使用Spring Cache的好处:
    • 提供基本的Cache抽象,方便切换各种底层Cache;
    • 通过注解Cache可以实现类似于事务一样,缓存逻辑透明的应用到我们的业务代码上,且只需要更少的代码就可以完成;
    • 提供事务回滚时也自动回滚缓存;
    • 支持比较复杂的缓存逻辑;

二、项目集成Spring Cache + Redis

  • 依赖
<!-- redis -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

开启@EnableCaching

1、配置方式

①第一种:配置类

@Configuration
@EnableCaching
public class RedisConfig {
    /**
     * 自定义key规则
     * @return
     */
    @Bean
    public KeyGenerator keyGenerator() {
        return new KeyGenerator() {
            @Override
            public Object generate(Object target, Method method, Object... params) {
                StringBuilder sb = new StringBuilder();
                sb.append(target.getClass().getName());
                sb.append(method.getName());
                for (Object obj : params) {
                    sb.append(obj.toString());
                }
                return sb.toString();
            }
        };
    }

    /**
     * 设置RedisTemplate规则
     * @param redisConnectionFactory
     * @return
     */
    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        //解决查询缓存转换异常的问题
        ObjectMapper om = new ObjectMapper();
        // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        //序列号key value
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
    /**
     * 设置CacheManager缓存规则
     * @param factory
     * @return
     */
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        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);
        // 配置序列化(解决乱码的问题),过期时间600秒
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
            .entryTtl(Duration.ofSeconds(600))
            .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
            .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
            .disableCachingNullValues();
        RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
            .cacheDefaults(config)
            .build();
        return cacheManager;
    }
}

②结合配置+配置文件

spring:
  cache:
  	#指定缓存类型为redis
    type: redis
    redis:
      # 指定redis中的过期时间为1h
      time-to-live: 3600000
      key-prefix: CACHE_   #缓存key前缀
      use-key-prefix: true #是否开启缓存key前缀
      cache-null-values: true #缓存空值,解决缓存穿透问题

默认使用jdk进行序列化(可读性差),默认ttl为-1永不过期,自定义序列化方式为JSON需要编写配置类

@Configuration
@EnableConfigurationProperties(CacheProperties.class)//拿到Redis在配置文件的配置
public class MyCacheConfig {
    @Bean
    public RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties) {
        //获取到配置文件中的配置信息
        CacheProperties.Redis redisProperties = cacheProperties.getRedis(); org.springframework.data.redis.cache.RedisCacheConfiguration config = org.springframework.data.redis.cache.RedisCacheConfiguration.defaultCacheConfig();
        //指定缓存序列化方式为json
        config = config.serializeValuesWith(
            RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
        //设置配置文件中的各项配置,如过期时间
        if (redisProperties.getTimeToLive() != null) {
            config = config.entryTtl(redisProperties.getTimeToLive());
        }
        if (redisProperties.getKeyPrefix() != null) {
            config = config.prefixKeysWith(redisProperties.getKeyPrefix());
        }
        if (!redisProperties.isCacheNullValues()) {
            config = config.disableCachingNullValues();
        }
        if (!redisProperties.isUseKeyPrefix()) {
            config = config.disableKeyPrefix();
        }
        return config;
    }
}

说明:

第一种,全自定义配置第二种,简单配置+自定义配置value值json转义

  • 对redis进行配置
#redis配置
spring.redis.host=47.120.237.184
spring.redis.port=6379
spring.redis.password=ach2ng@123356
spring.redis.database= 0
spring.redis.timeout=1800000
#redis池设置
spring.redis.lettuce.pool.max-active=20
spring.redis.lettuce.pool.max-wait=-1
#最大阻塞等待时间(负数表示没限制)
spring.redis.lettuce.pool.max-idle=5
spring.redis.lettuce.pool.min-idle=0

三、使用Spring Cache

@Cacheable

根据方法对其返回结果进行缓存,下次请求时,如果缓存存在,则直接读取缓存数据返回;如果缓存不存在,则执行方法,并把返回的结果存入缓存中。一般用在查询方法上。

属性/方法名 解释
value 缓存名,必填,它指定了你的缓存存放在哪块分区,可多指定,如{"catagory","xxxx",....}
cacheNames 与 value 差不多,二选一即可
key 可选属性,可以使用 SpEL 标签自定义缓存的key,如:#root.methodName【用方法名作为key】
sync 默认false,为true时,会让操作被同步保护,可避免缓存击穿问题

@CachePut

使用该注解标志的方法,每次都会执行,并将结果存入指定的缓存中。其他方法可以直接从响应的缓存中读取缓存数据,而不需要再去查询数据库。一般用在新增方法上。

属性/方法名
value 缓存名,必填,它指定了你的缓存存放在==哪块分区,==可多指定,如{"catagory","xxxx",....}
cacheNames 与 value 差不多,二选一即可
key 可选属性,可以使用 SpEL 标签自定义缓存的key

@CacheEvict

使用该注解标志的方法,会清空指定的缓存。一般用在更新或者删除方法上

属性/方法名 解释
value 缓存名,必填,它指定了你的缓存存放在==哪块分区,==可多指定,如{"catagory","xxxx",....}
cacheNames 与 value 差不多,二选一即可
key 可选属性,可以使用 SpEL 标签自定义缓存的key key如果是字符串"''",【请加上单引号】
allEntries 是否清空所有缓存,默认为 false。如果指定为 true,则方法调用后将立即清空所有的缓存 allEntries = true,会对删除value分区里的所有数据
beforeInvocation 是否在方法执行前就清空,默认为 false。如果指定为 true,则在方法执行前就会清空缓存

@Caching

可组合使用以上注解,如:

//组合了删除缓存的@CacheEvict注解,同时删除两个
@Cacheing(evict=
          {@CacheEvict(value="a"),key="'getLists'"}),
		  {@CacheEvict(value="b"),key="'getArr'"})
         )

使用举例 失效模式: 更新操作后,删除缓存 双写模式: 更新操作后,新增缓存,掩盖

四、SpringCache原理与不足

1、读模式

缓存穿透:

查询一个null数据。

解决方案:缓存空数据

可通过spring.cache.redis.cache-null-values=true

缓存击穿:

大量并发进来同时查询一个正好过期的数据。

解决方案: 加锁 ? 默认是无加锁的;

使用sync = true来解决击穿问题

缓存雪崩:

大量的key同时过期。

解决方案:加随机时间,time-to-live: 3600000。

2、写模式:(缓存与数据库一致)

  • 读写加锁。
  • 引入Canal,感知到MySQL的更新去更新Redis
  • 读多写多,直接去数据库查询就行

五、总结

常规数据(读多写少,即时性,一致性要求不高的数据,完全可以使用Spring-Cache):

写模式(只要缓存的数据有过期时间就足够了)

特殊数据:

特殊设计(读写锁、redis分布锁等

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • JAVA垃圾收集器与内存分配策略详解

    引言 垃圾收集技术并不是Java语言首创的,1960年诞生于MIT的Lisp是第一门真正使用内存动态分配和垃圾收集技术的语言.垃圾收集技术需要考虑的三个问题是: 1.哪些内存需要回收 2.什么时候回收 3.如何回收 java内存运行时区域的分布,其中程序计数器,虚拟机栈,本地方法区都是随着线程而生,随线程而灭,所以这几个区域就不需要过多考虑回收问题.但是堆和方法区就不一样了,只有在程序运行期间我们才知道会创建哪些对象,这部分内存的分配和回收都是动态的.垃圾收集器所关注的就是这部分内存. 一 对象

  • 使用jvisualvm配合Visual GC插件监控Java程序详细总结

    jvisualvm介绍 VisualVM(All-in-One Java Troubleshooting Tool)是到目前为止随JDK发布的功能最强大的运行监视和故障处理程序,它提供了运行监视.故障处理.性能分析(Profiling)等功能.VisuaIVM有一个很大的优点:不需要被监视的程序基于特殊Agent运 行,因此它对应用程序的实际性能的影响很小,使得它可以直接应用在生产环境中. jdk8的文档中https://docs.oracle.com/javase/8/docs/technot

  • 深入理解Java SpringCloud Ribbon 负载均衡

    目录 前言 1.抛出问题 2.源码解析 2.1.LoadBalancerIntercepor 2.2.LoadBalancerClient 2.3.负载均衡策略IRule 2.4.总结 3.负载均衡策略 总结 前言 该技术博客是关于黑马视频教程的笔记总结! 服务消费者需要通过RestTemplate调用注册中心(Eureka)的服务提供者,但当同一服务名称的服务有多个的时候,我们的服务消费者应该调用哪一个服务呢?这时候就需要我们学习理解Ribbon负载均衡的实现原理. 当我们在RestTempl

  • 解析Java内存分配和回收策略以及MinorGC、MajorGC、FullGC

    目录 对象内存分配与回收策略 对象何时进入新生代.老年代 三种GC介绍 MinorGC Major GC/Full GC: 图示GC过程 对象内存分配与回收策略 对象的内存分配,往大方向讲,就是在堆上分配[但也可能经过JIT编译后被拆散为标量类型并间接地栈上分配),对象主要分配在新生代的Eden区上,如果启动了本地线程分配缓冲,将按线程优先在TLAB上分配.少数情况下也可能会直接分配在老年代中. 对象优先分配在Eden区,当Eden区可用空间不够时会进行MinorGC 大对象直接进入老年代:大对

  • 浅谈JAVA8给我带了什么——流的概念和收集器

    到现在为止,笔者不敢给流下定义,从概念来讲他应该也是一种数据元素才是.可是在我们前面的代码例子中我们可以看到他更多的好像在表示他是一组处理数据的行为组合.这让笔者很难去理解他的定义.所以笔者不表态.各位同志自行理解吧. 在没有流以前,处理集合里面的数据一般都会用到显示的迭代器.用一下前面学生的例子吧.目标是获得学分大于5的前俩位同学. package com.aomi; import java.util.ArrayList; import java.util.Iterator; import j

  • Java SpringBoot整合SpringCloud

    目录 1. SpringCloud特点 2. 分布式系统的三个指标CAP 3. Eureka 4. SpringCloud Demo 4.1 registry 4.2 api 4.3 provider 4.4 consumer 4.5 POSTMAN一下 1. SpringCloud特点 SpringCloud专注于为典型的用例和扩展机制提供良好的开箱即用体验,以涵盖其他情况: 分布式/版本化配置 服务注册和发现 Eureka 路由 Zuul 服务到服务的呼叫 负载均衡 Ribbon 断路器 H

  • Java8 Stream Collectors收集器使用方法解析

    Collectors.toMap: Student studentA = new Student("20190001","小明"); Student studentB = new Student("20190002","小红"); Student studentC = new Student("20190003","小丁"); //Function.identity() 获取这个对象本身

  • java中的GC收集器详情

    目录 1.GC(Garbage collection ) 2.GC算法 2.1标记活动对象 2.2 删除空闲对象 2.3 标记清除(Mark-Sweep) 2.4 清除压缩(Mark-Sweep-Compact) 2.5 标记和复制 3.JVM GC 3.1 JVM GC事件 3.2 Serial GC 3.3 Parallel GC 3.4 Concurrent Mark and Sweep 3.5 G1 –垃圾优先 4.总结 1.GC(Garbage collection ) 程序内存管理分

  • java 8如何自定义收集器(collector)详解

    需求: 将 一个容器List<Bean> 按照一定的字段进行分组,分组过后的值为特定的BEAN 里面的属性例如: 假定有这样一个Bean public class SubjectOberser{ private String subjectKey; private AbstractObserver abstractObserver; ...geter seter 方法... } 我们需要按照 subjectKey 进行分组,分组过后的内容 应该为这样一个容器Map<String,List

  • Java SpringCache+Redis缓存数据详解

    目录 前言 一.什么是SpringCache 二.项目集成Spring Cache + Redis 1.配置方式 三.使用Spring Cache 四.SpringCache原理与不足 1.读模式 2.写模式:(缓存与数据库一致) 五.总结 前言 这几天学习谷粒商城又再次的回顾了一次SpringCache,之前在学习谷粒学院的时候其实已经学习了一次了!!! 这里就对自己学过来的内容进行一次的总结和归纳!!! 一.什么是SpringCache Spring Cache 是一个非常优秀的缓存组件.自

  • C基础 redis缓存访问详解

    引言 先说redis安装, 这里采用的环境是. Linux version 4.4.0-22-generic (buildd@lgw01-41) (gcc version 5.3.1 20160413 (Ubuntu 5.3.1-14ubuntu2) ) #40-Ubuntu SMP Thu May 12 22:03:46 UTC 2016 对于 ubuntu 安装 redis是非常简单的. 这里采用源码安装. 安装代码如下 wget http://download.redis.io/relea

  • Java使用Redis及其优化详解

    目录 前言 开启远程连接 Jedis连接Redis 封装Jedis进行操作 前言 所有坚韧不拔的努力迟早会取得报酬的.-- 安格尔 开启远程连接 Redis默认是不支持远程连接的,这里需要手动开启远程连接. 关闭本机IP绑定,允许远程连接.找到redis.conf中的bind:127.0.0.1将其注释. 开启密码校验.找到redis.conf中的requirepass去掉其注释并设置密码. Jedis连接Redis 创建一个Maven项目,导入Jedis依赖. <dependency> &l

  • Java MyBatis本地缓存原理详解

    目录 背景 发现问题 复现 解决问题 探究缓存的原理 Sql查询部分深入 初见缓存 告一段落 番外篇-Myabtis创建CacheKey的算法. 构造方法 结束语 背景 出现了一次生产事故,事情是这样的,我们有一个项目,Java访问数据库的框架使用的是MyBatis.然后一个业务员在系统中查询了一个订单,发现这个订单是未支付的状态,于是业务员联系客户,让客户支付,客户支付完成后,业务员又去系统查询,结果还是未支付状态,刷新了页面也是一样,不过过了一会就好了.业务员把这个延迟问题,反馈给了我们.我

  • Spring Boot 基于注解的 Redis 缓存使用详解

    看文本之前,请先确定你看过上一篇文章<Spring Boot Redis 集成配置>并保证 Redis 集成后正常可用,因为本文是基于上文继续增加的代码. 一.创建 Caching 配置类 RedisKeys.Java package com.shanhy.example.redis; import java.util.HashMap; import java.util.Map; import javax.annotation.PostConstruct; import org.springf

  • Python 注解方式实现缓存数据详解

    目录 背景 拿来即用 实践过程 通过装饰器类简化代码 总结 背景 每次加载数据都要重新Load,想通过加入的注解方式开发缓存机制,每次缓存不用写代码了 缺点:目前仅支持一个返回值,虽然能弄成字典,但是已经满足个人需求,没动力改(狗头). 拿来即用 新建文件 Cache.py class Cache: def __init__(self, cache_path='.', nocache=False): self.cache_path = cache_path self.cache = not no

  • Java Spring MVC获取请求数据详解操作

    目录 1. 获得请求参数 2. 获得基本类型参数 3. 获得POJO类型参数 4. 获得数组类型参数 5. 获得集合类型参数 6. 请求数据乱码问题 7. 参数绑定注解 @requestParam 8. 获得Restful风格的参数 9. 自定义类型转换器 1.定义转换器类实现Converter接口 2.在配置文件中声明转换器 3.在<annotation-driven>中引用转换器 10. 获得Servlet相关API 11. 获得请求头 11.1 @RequestHeader 11.2 @

  • SpringBoot自定义Redis实现缓存序列化详解

    目录 1.自定义RedisTemplate 1.1.Redis API默认序列化机制 1.2.自定义RedisTemplate序列化机制 1.3.效果测试 2.自定义RedisCacheManager 2.1.Redis注解默认序列化机制 2.2.自定义RedisCacheManager 刚刚完成了Spring Boot整合Redis进行了数据的缓存管理,但缓存管理的实体类数据使用的是JDK序列化方式,不便于使用可视化管理工具进行查看和管理. 接下来分别针对基于注解的Redis缓存实现和基于AP

  • Laravel操作redis和缓存操作详解

    目录 一:操作redis 1:redis拓展安装 2:配置redis 3:操作redis 二:缓存操作 1:缓存配置 2:缓存操作 一:操作redis 1:redis拓展安装 composer require predis/predis 或者你也可以通过 PECL 安装 PhpRedis PHP 扩展,安装方法比较复杂,个人不推荐 2:配置redis 在config/database.php文件中配置redis (1):单个redis配置 'redis' => [ 'client' => en

  • java解析JSON数据详解

    JSON是目前最流行的轻量级数据交换语言(没有之一).尽管他是javaScript的一个子集.但由于其是独立与语言的文本格式,它几乎可以被所有编程语言所支持. 以下是对java语言中解析json数据的总结. 要解析json,首先要导入解析json的工具类. import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; 我们都知道JSON中有json对象与json数组(json数据就是js

随机推荐