redis缓存优化—SpringCache

1. 问题引入

问题:所有数据从数据库MySQL直接查询,可能会存在问题:

  • 频繁访问数据库,
  • 数据库访问压力大,系统性能下降。
  • 用户体验较差

解决方法:通过Redis缓存技术

  • 好处和优势:
    1. 降低数据库的访问压力;
    2. 提高系统的访问性能;
    3. 从而提升用户体验。

缓存优化思路

  1. 先查询缓存
  2. 如果缓存中有数据则会直接返回
  3. 如果缓存没有数据,则需要查询数据库,再将数据库查询的结果缓存在redis中。
  4. 如果数据库中的数据发生新增、修改、删除,缓存数据应该清空,保证和数据库保持一致。
  5. 清空之后,下一次查询数据库,最新的数据就缓存到了redis(走第一步逻辑,最多只查询数据库一次)

2. SpringCache

  • Spring Cache是一个框架,实现了基于注解的缓存功能,只需要简单地加一个注解,就能实现缓存功能,大大简化我们在业务中操作缓存的代码。

  • Spring Cache只是提供了一层抽象,底层可以切换不同的cache实现。具体就是通过CacheManager接口来统一不同的缓存技术。CacheManager是Spring提供的各种缓存技术抽象接口。

针对不同的缓存技术需要实现不同的CacheManager:

CacheManager描述
EhCacheCacheManager使用EhCache作为缓存技术
GuavaCacheManager使用Google的GuavaCache作为缓存技术
RedisCacheManager使用Redis作为缓存技术

2.1 注解@EnableCaching

  • @EnableCaching:在引导类上加该注解,就代表当前项目开启缓存注解功能。

2.2 注解@CachePut

  • @CachePut:将方法返回值,放入缓存
  1. 在save方法上加上注解@CachePut
    • 当前save方法是用来保存用户信息的,我们希望在该用户信息保存到数据库的同时,也往缓存中缓存一份数据,我们可以在save方法上加上注解 @CachePut
    /**
     * @CachePut:
     *  作用:将方法返回值,存入缓存
     *  cacheNames:缓存的名称,每个缓存下面可以有很多key
     *  key:缓存的key
     */
    @CachePut(cacheNames = "cacheUser",key = "#user.id")
    @PostMapping
    public User save(User user){
        userService.save(user);
        return user;
    }

key的写法如下: #user.id : #user指的是方法形参的名称, id指的是user的id属性 , 也就是使用user的id属性作为key ; #user.name: #user指的是方法形参的名称, name指的是user的name属性 ,也就是使用user的name属性作为key ;

注:最终的数据是缓存在ConcurrentHashMap中,那么当我们的服务器重启之后,缓存中的数据就会丢失,使用Redis来缓存就不存在丢失。

2.3 注解@CacheEvict

  • @CacheEvict:清理指定缓存
  1. 在 delete 方法上加注解@CacheEvict
    • 当我们在删除数据库user表的数据的时候,我们需要删除缓存中对应的数据,此时就可以使用@CacheEvict注解
    /**
     * @CacheEvict:
     *  作用:清理指定缓存
     *  cacheNames:缓存的名称,每个缓存下面可以有很多key
     *  key:缓存的key
     */
    @CacheEvict(cacheNames = "cacheUser" ,key = "#id")
    @DeleteMapping("/{id}")
    public void delete(@PathVariable Long id){
        userService.removeById(id);
    }
  1. 在 update 方法上加注解@CacheEvict
    • 更新数据后,数据库数据发生了改变,需要将缓存中对应的数据删掉。
    @CacheEvict(cacheNames = "cacheUser",key = "#user")
    @PutMapping
    public User update(User user){
        userService.updateById(user);
        return user;
    }
  • 清除某一份缓存下所有的数据,可以指定@CacheEvict中的一个属性 allEnties,将其设置为true即可。
@CacheEvict(value = "cacheUser",allEntries = true) //清除cacheUser名称下,所有的缓存数据

2.4 注解@Cacheable

  • @Cacheable:如果缓存有数据,此方法就不再执行,如果没有数据,就先查询数据库,然后自动存入缓存,下次就直接返回。

  • 特点:

    1. 可以标记在方法上,也可以标记在类上。
    2. 当标记在方法上时表示该方法是支持缓存的,当标记在类上时则表示该类所有的方法都是支持缓存的。
    3. 对于一个支持缓存的方法,Spring会在其被调用后将其返回值添加缓存,以保证下次利用同样的参数来执行该方法时可以直接从缓存中获取结果,而不需要再次执行该方法。
    4. Spring在缓存方法的返回值时是以键值对进行缓存的,值就是方法的返回结果,至于键的话,Spring又支持两种策略,默认策略和自定义策略。

  1. 在getById上加注解@Cacheable
  • condition : 表示满足什么条件, 再进行缓存 ;
  • unless:满足条件则不缓存
    /**
     * @Cacheable 在方法执行前spring先查看缓存中是否有数据,如果有数据,则直接返回缓存数据;没有数据会调用方法并将方法返回值放到缓存中
     * cacheNames:缓存的名称,每个缓存下面可以有很多key
     * key:缓存的key
     * condition:条件,满足条件时才缓存数据
	 * unless:满足条件则不缓存
     */
//@Cacheable(cacheNames = "cacheUser",key = "#id", unless = "#result == null")满足条件则不缓存
    @Cacheable(cacheNames = "cacheUser",key = "#id")
    @GetMapping("/{id}")
    public User getById(@PathVariable Long id){
        User user = userService.getById(id);
        return user;
    }
  1. 在list方法上加注解@Cacheable
  • 如果list查询两个条件,需要在缓存的key包含两个参数
    /**
     * 带条件查询
     * @param user
     * @return
     */
    @Cacheable(value = "userCache",key = "#user.id + '_' + #user.name")
    @GetMapping("/list")
    public List<User> list(User user){
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(user.getId() != null,User::getId,user.getId());
        queryWrapper.eq(user.getName() != null,User::getName,user.getName());
        List<User> list = userService.list(queryWrapper);
        return list;
    }

2.5 集成redis

上述默认的使用ConcurrentHashMap做缓存时,服务重启之后,之前缓存的数据就全部丢失了,操作起来并不友好。

  1. 引入pom依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
  1. yml配置文件
    spring:
      redis:
        host: 127.0.0.1
        port: 6379
        #password: 123456
        database: 0
      cache:
        redis:
          time-to-live: 1800000   #设置缓存过期时间,可选 (单位是ms,  1800s = 30min)
  • 小结:
    • 注解@Cacheable和@CachePut都可以保存缓存键值对,它们只能运用于有返回值的方法中;
    • 删除缓存key的@CacheEvict则可以用在void的方法上,因为它并不需要去保存任何值;
    • 对于查询,我们会考虑使用@Cacheable;
    • 对于插入和修改,我们会考虑使用@CachePut 或者 @CacheEvict (先删再查 );
    • 对于删除,我们会考虑采用使用@CacheEvict。

2.6 序列化异常

@Cacheable 会将方法的返回值缓存在Redis中,而在Redis中存储对象,该对象是需要被序列化的,而对象要想被成功的序列化,就必须得实现Serializable 接口。而当前我们定义的R,并未实现 Serializable 接口。因此R、实现Serializable接口

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
# demoWeb 一个基于SpringMVC的web框架 1.0.5 从web项目迁移成maven项目 1.0.6 增加菜单框架ext实现,类路径调整 1.0.7 增加http工具类,demo例子 1.0.8 socket工具类,权限组件,菜单组件,jdbc分页支持多种数据库,ant路径工具类,增加jquery easyUI 1.0.9 版本管理,服务根路径工具类,文件上传工具类 1.0.10 集成ueditor在线编辑器 1.0.11 地址联动 1.0.12 Excel工具类 Word工具类 Java NIO实现socket工具类 分布式session jdk升级到1.7 嵌入式redis服务(只支持linux) 1.0.13 修改默认的beanName生成策略,controller参数扩展 1.0.14 分布式session使用zookeeper 1.0.15 zookeeper工具类优化 增加工具类 1.0.16 页面html标志修改 httpclient中文支持 工具类增强(zip,reflect,thread) 1.0.17 ftp服务端和客户端工具类,配置文件maven和web项目路径统一 1.1.0 soapui工具类(web版本) properties等工具类 1.1.1 工具类数据校验 jsp自定义标签 Spring自定义注解 默认requestMapping 1.1.2 代码生成器 1.1.3 首页修改 dateformat.js 时间参数转换 SpringMVC配置文件集中 快递参数接口 1.1.4 des加解密字符串和文件 1.1.5 redis 加锁,redis升级成2.8.2 freemarker工具类 1.1.6 spring websocket 实现在线聊天 maven升级jdk1.8 jetty9.2.4 web升级jdk1.7 tomcat7 1.1.7(maven only) 包名修改 从此不再支持web版本,只支持maven版本 1.1.8 jquery 图片预览插件 图片滚动显示插件 1.1.9 jquery实现鼠标在按钮上显示窗口,离开窗口和按钮时消失 1.1.10 rabbitMQ集成 视频截图 图片缩略图旋转 集成Mybatis 使用数据库连接池druid dubbo使用 1.1.11 集成Spring Cache,FastJson Spring Cache增加redis缓存实现 Mybatis使用二级缓存,增加redis实现 增加reactJs 增加Mybatis插件pageHelper,Mapper doc内有相关文档

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mr.han、

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值