springboot与缓存(整合redis)

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
简介: 缓存就是数据交换的缓冲区(称作:Cache),他把一些外存上的数据保存在内存上,为什么保存在内存上,我们运行的所有程序里面的变量都是存放在内存中的,所以如果想将值放入内存上,可以通过变量的方式存储。在JAVA中一些缓存一般都是通过Map集合来实现的。

一、什么是缓存

缓存就是数据交换的缓冲区(称作:Cache),他把一些外存上的数据保存在内存上,为什么保存在内存上,我们运行的所有程序里面的变量都是存放在内存中的,所以如果想将值放入内存上,可以通过变量的方式存储。在JAVA中一些缓存一般都是通过Map集合来实现的。

缓存在不同的场景下,作用是不一样的具体举例说明:
✔  操作系统磁盘缓存 ——> 减少磁盘机械操作。
✔  数据库缓存——>减少文件系统IO。
✔  应用程序缓存——>减少对数据库的查询。
✔  Web服务器缓存——>减少应用服务器请求。
✔  客户端浏览器缓存——>减少对网站的访问。

具体关于缓存的详细介绍以及缓存的面试问题可以参考这篇博客

三、几个重要概念&缓存注解

1、Cache:

缓存接口,定义缓存操作。实现有:RedisCache、EhCacheCache、ConcurrentMapCache等

2、CacheManager

缓存管理器,管理各种缓存(Cache)组件

3、@Cacheable

主要针对方法配置,能够根据方法的请求参数对其结果进行缓存

(后面会细说该注解)

4、@CacheEvict

清空缓存

5、@CachePut

保证方法被调用,又希望结果被缓存。

6、@EnableCaching

开启基于注解的缓存

7、keyGenerator

缓存数据时key生成策略

8、serialize

缓存数据时value序列化策略

9、@Cacheable/@CachePut/@CacheEvict 主要的参数

网络异常,图片无法展示
|

网络异常,图片无法展示
|

四、springboot整合redis实现缓存

1、引入依赖

在pom.xml中引入spring-boot-starter-data-redis依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2、配置redis连接地址

在application.yml或者application.properties中配置redis连接地址

这里还需要配置一下数据库的地址,方便测试使用

application.properties配置

spring.datasource.url=jdbc:mysql://MySQL的主机地址:3306/数据库名
spring.datasource.username=root
spring.datasource.password=密码
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
# 启用mybatis的命名策略(即驼峰命名法)
mybatis.configuration.map-underscore-to-camel-case=true
logging.level.com.atguigu.cache.mapper=debug
debug=true
spring.redis.host=redis主机地址

application.yml配置:

spring:
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql://MySQL的主机地址:3306/数据库名
    driver-class-name: com.mysql.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource #配置Druid数据源
    #   数据源其他配置
    initialSize: 5
    minIdle: 5
    maxActive: 20
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1 FROM DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true
    #   配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
    filters: stat,wall,log4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
  redis:
    host: redis主机地址
#mybatis:
#  config-location: classpath:mybatis/mybatis-config.xml
# 开启驼峰命名
mybatis:
  configuration:
    map-underscore-to-camel-case: true
logging:
  level:
    com.canghe.springboot.mapper: debug
debug: true
#  mapper-locations: classpath:mybatis/mapper/*.xml

3、在虚拟机或者云服务器上安装redis

可以直接通过docker安装redis,并配置端口

4、使用RestTemplate操作redis

@Autowired
    StringRedisTemplate stringRedisTemplate;//操作k-v都是字符串
    @Autowired
    RedisTemplate redisTemplate;//操作k-v对象的

Redis常见的五大数据类型

String(字符串) 、list(列表)、set(集合)、hash(散列)、Zset(有序集合)

  1. redisTemplate.opsForValue();//操作字符串
  2. redisTemplate.opsForHash();//操作hash
  3. redisTemplate.opsForList();//操作list
  4. redisTemplate.opsForSet();//操作set
  5. redisTemplate.opsForZSet();//操作有序set

测试代码:

@Test
    public void test01() {
//        stringRedisTemplate.opsForValue().append("key","helloword");
//        String msg = stringRedisTemplate.opsForValue().get("key");
//        System.out.println("msg:"+msg);
        stringRedisTemplate.opsForList().leftPush("firstList","1");
        stringRedisTemplate.opsForList().leftPush("firstList","2");
    }

五、@Cacheable注解

1、运行流程

1、方法运行之前,先去查询Cache(缓存组件),按照cacheNames指定的名字获取;(CacheManager先获取相应的缓存),第一次获取缓存如果没有Cache组件会自动创建。
2、去Cache中查找缓存的内容,使用一个key,默认就是方法的参数; key是按照某种策略生成的;默认是使用keyGenerator生成的,默认使用SimpleKeyGenerator生成key; SimpleKeyGenerator生成key的默认策略;
如果没有参数;key=new SimpleKey();
如果有一个参数:key=参数的值
如果有多个参数:key=new SimpleKey(params);

3、没有查到缓存就调用目标方法;

4、将目标方法返回的结果,放进缓存中

@Cacheable标注的方法执行之前先来检查缓存中有没有这个数据,默认按照参数的值作为key去查询缓存,**
如果没有就运行方法并将结果放入缓存;以后再来调用就可以直接使用缓存中的数据;**

2、核心

1)、使用CacheManager【ConcurrentMapCacheManager】按照名字得到Cache【ConcurrentMapCache】组件
2)、key使用keyGenerator生成的,默认是SimpleKeyGenerator

3、几个属性

  • cacheNames/value:指定缓存组件的名字;将方法的返回结果放在哪个缓存中,是数组的方式,可以指定多个缓存;
  • key:缓存数据使用的key;可以用它来指定。默认是使用方法参数的值  1-方法的返回值, 编写SpEL; #i d;参数id的值   #a0  #p0  #root.args[0]    getEmp[2]
  • keyGenerator:key的生成器;可以自己指定key的生成器的组件id,key/keyGenerator:二选一使用;
  • cacheManager:指定缓存管理器;或者cacheResolver指定获取解析器
  • condition:指定符合条件的情况下才缓存; condition = "#a0>1":第一个参数的值》1的时候才进行缓存
  • unless:否定缓存;当unless指定的条件为true,方法的返回值就不会被缓存;可以获取到结果进行判断
unless = "#result == null"
     *              unless = "#a0==2":如果第一个参数的值是2,结果不缓存;


  • sync:是否使用异步模式

@Cacheable例子:

@Cacheable(value = {"emp"}/*,keyGenerator = "myKeyGenerator",condition = "#a0>1",unless = "#a0==2"*/)
    public Employee getEmp(Integer id){
        System.out.println("查询"+id+"号员工");
        Employee emp = employeeMapper.getEmpById(id);
        return emp;
    }

六、@CachePut

1、启用场景

既调用方法,又更新缓存数据;同步更新缓存,修改了数据库的某个数据,同时更新缓存;

2、运行时机

  • 先调用目标方法
  • 将目标方法的结果缓存起来

3、测试步骤

1、查询1号员工;查到的结果会放在缓存中;
key:1  value:lastName:张三
2、以后查询还是之前的结果
3、更新1号员工;【lastName:zhangsan;gender:0】
将方法的返回值也放进缓存了;
key:传入的employee对象  值:返回的employee对象;
4、查询1号员工?
应该是更新后的员工;
key = "#employee.id":使用传入的参数的员工id;
key = "#result.id":使用返回后的id
@Cacheable的key是不能用#result
为什么是没更新前的?【1号员工没有在缓存中更新】

@CachePut(/*value = "emp",*/key = "#result.id")
    public Employee updateEmp(Employee employee){
        System.out.println("updateEmp:"+employee);
        employeeMapper.updateEmp(employee);
        return employee;
    }

七、@CacheEvict

缓存清除

/**
     * @CacheEvict:缓存清除
     *  key:指定要清除的数据
     *  allEntries = true:指定清除这个缓存中所有的数据
     *  beforeInvocation = false:缓存的清除是否在方法之前执行
     *      默认代表缓存清除操作是在方法执行之后执行;如果出现异常缓存就不会清除
     *
     *  beforeInvocation = true:
     *      代表清除缓存操作是在方法运行之前执行,无论方法是否出现异常,缓存都清除
     *
     *
     */
    @CacheEvict(value="emp",beforeInvocation = true/*key = "#id",*/)
    public void deleteEmp(Integer id){
        System.out.println("deleteEmp:"+id);
        //employeeMapper.deleteEmpById(id);
        int i = 10/0;
    }

八、@Caching

目录
相关文章
|
27天前
|
存储 缓存 NoSQL
Redis专题-实战篇二-商户查询缓存
本文介绍了缓存的基本概念、应用场景及实现方式,涵盖Redis缓存设计、缓存更新策略、缓存穿透问题及其解决方案。重点讲解了缓存空对象与布隆过滤器的使用,并通过代码示例演示了商铺查询的缓存优化实践。
119 1
Redis专题-实战篇二-商户查询缓存
|
11天前
|
缓存 负载均衡 监控
135_负载均衡:Redis缓存 - 提高缓存命中率的配置与最佳实践
在现代大型语言模型(LLM)部署架构中,缓存系统扮演着至关重要的角色。随着LLM应用规模的不断扩大和用户需求的持续增长,如何构建高效、可靠的缓存架构成为系统性能优化的核心挑战。Redis作为业界领先的内存数据库,因其高性能、丰富的数据结构和灵活的配置选项,已成为LLM部署中首选的缓存解决方案。
|
13天前
|
缓存 运维 监控
Redis 7.0 高性能缓存架构设计与优化
🌟蒋星熠Jaxonic,技术宇宙中的星际旅人。深耕Redis 7.0高性能缓存架构,探索函数化编程、多层缓存、集群优化与分片消息系统,用代码在二进制星河中谱写极客诗篇。
|
27天前
|
缓存 NoSQL 关系型数据库
Redis缓存和分布式锁
Redis 是一种高性能的键值存储系统,广泛用于缓存、消息队列和内存数据库。其典型应用包括缓解关系型数据库压力,通过缓存热点数据提高查询效率,支持高并发访问。此外,Redis 还可用于实现分布式锁,解决分布式系统中的资源竞争问题。文章还探讨了缓存的更新策略、缓存穿透与雪崩的解决方案,以及 Redlock 算法等关键技术。
|
5月前
|
缓存 NoSQL 关系型数据库
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
|
5月前
|
缓存 NoSQL Java
Redis+Caffeine构建高性能二级缓存
大家好,我是摘星。今天为大家带来的是Redis+Caffeine构建高性能二级缓存,废话不多说直接开始~
776 0
|
5月前
|
消息中间件 缓存 NoSQL
基于Spring Data Redis与RabbitMQ实现字符串缓存和计数功能(数据同步)
总的来说,借助Spring Data Redis和RabbitMQ,我们可以轻松实现字符串缓存和计数的功能。而关键的部分不过是一些"厨房的套路",一旦你掌握了这些套路,那么你就像厨师一样可以准备出一道道饕餮美食了。通过这种方式促进数据处理效率无疑将大大提高我们的生产力。
205 32
|
5月前
|
缓存 NoSQL Java
Redis:现代服务端开发的缓存基石与电商实践-优雅草卓伊凡
Redis:现代服务端开发的缓存基石与电商实践-优雅草卓伊凡
116 5
Redis:现代服务端开发的缓存基石与电商实践-优雅草卓伊凡
|
7月前
|
缓存 NoSQL Java
Redis应用—8.相关的缓存框架
本文介绍了Ehcache和Guava Cache两个缓存框架及其使用方法,以及如何自定义缓存。主要内容包括:Ehcache缓存框架、Guava Cache缓存框架、自定义缓存。总结:Ehcache适合用作本地缓存或与Redis结合使用,Guava Cache则提供了更灵活的缓存管理和更高的并发性能。自定义缓存可以根据具体需求选择不同的数据结构和引用类型来实现特定的缓存策略。
424 16
Redis应用—8.相关的缓存框架
|
7月前
|
缓存 监控 NoSQL
Redis--缓存击穿、缓存穿透、缓存雪崩
缓存击穿、缓存穿透和缓存雪崩是Redis使用过程中可能遇到的常见问题。理解这些问题的成因并采取相应的解决措施,可以有效提升系统的稳定性和性能。在实际应用中,应根据具体场景,选择合适的解决方案,并持续监控和优化缓存策略,以应对不断变化的业务需求。
1366 29