SpringCache缓存

简介: SpringCache缓存

一:为什么需要缓存

前台请求,后台先从缓存中取数据,取到直接返回结果,取不到时从数据库中取,数据库取到更新缓存,并返回结果,数据库也没取到,那直接返回空结果。

使用缓存是一个很“高性价比”的性能优化方式,尤其是对于有大量重复查询的程序来说。通常来说,在WEB后端应用程序来说,

耗时比较大的往往有两个地方:

1、查数据库;

2、调用其它服务的API(因为其它服务最终也要去做查数据库等耗时操作);

重复查询也有两种:

1、我们在应用程序中代码写得不好,写的for循环,可能每次循环都用重复的参数去查询了。

2、大量的相同或相似请求造成的。比如资讯网站首页的文章列表、电商网站首页的商品列表、微博等社交媒体热搜的文章等等,当大量的用户都去请求同样的接口,同样的数据,如果每次都去查数据库,那对数据库来说是一个不可承受的压力。所以我们通常会把高频的查询进行缓存,我们称它为“热点”

二:SpringCache介绍

存有诸多的好处,于是大家就摩拳擦掌准备给自己的应用加上缓存的功能。但是网上一搜却发现缓存的框架太多了,各有各的优势,比如==Redis[中央缓存-远程缓存]==、Memcached、Guava、Caffeine[本地缓存]等等。

如果我们的程序想要使用缓存,就要与这些框架耦合。聪明的架构师已经在利用接口来降低耦合了,利用面向对象的抽象和多态的特性,做到业务代码与具体的框架分离。

但我们仍然需要显式地在代码中去调用与缓存有关的接口和方法,在合适的时候插入数据到缓存里,在合适的时候从缓存中读取数据。想一想「AOP」的适用场景,这不就是天生就应该AOP去做的吗?

自Spring 3.1起,提供了类似于 @Transactional 注解事务的注解Cache支持,且提供了Cache抽象,在此之前一般通过AOP实现

使用springcache的好处:

  • 提供基本的Cache抽象,方便切换各种底层Cache;
  • 通过注解Cache可以实现类似于事务一样,缓存逻辑透明的应用到我们的业务代码上,且只需要更少的代码就可以完成;
  • 提供事务回滚时也自动回滚缓存;
  • 支持比较复杂的缓存逻辑;

所以说 Spring Cache就是一个缓存框架。它利用了AOP(将缓存逻辑与服务逻辑解耦),实现了基于注解的缓存功能(声明式缓存),并且进行了合理的抽象,业务代码不用关心底层是使用了什么缓存框架,只需要简单地加一个注解,就能实现缓存功能了。而且Spring Cache也提供了很多默认的配置,用户可以快速将缓存集成到项目中;

三: springcache注解

3.1:@Cacheable注解

==如果缓存中没有:查询数据库,存储缓存,返回结果,==

==如果缓存中有:直接返回结果==

作用:可以用来进行缓存的写入,将结果存储在缓存中,以便于在后续调用的时候可以直接返回缓存中的值,而不必再执行实际的方法。 最简单的使用方式,注解名称=缓存名称,使用例子如下:

@Service
@CacheConfig(cacheNames = "role")//提取缓存的前缀配置
public class RoleServiceImpl implements IRoleService {
 
    @Autowired
    private RoleMapper roleMapper;
 
    /**
     * <p>
     * 几个属性:
     * a)cacheNames/value:指定缓存组件的名字
     *      cacheNames = {"role"}可以使用多个参数,是数组的形式,可以指定多个缓存
     * b)key:缓存数据使用的key,可以用他来指定。默认是使用方法参数的值
     *      编写SpEl:   #id  #a0,#po,#argrs[0]  "0"代表参数的索引
     *      #result  方法执行后的返回值
     *      #root.methodName   方法名
     *      key = "#root.methodName+'['+#id+']'"
     * e)condition:指定符合缓存的条件
     *      condition = "#id>0 and #root.methodName eq 'aaa'" 可以多条件判断
     * f)unless: 否定缓存,当unless的条件为true,方法结果不会被缓存,可以获取结果进行判断
     *      unless = "#result==null",结果为null,就不缓存
     */
    @Override
    //@Cacheable(cacheNames = "role", key = "#id",condition = "#id>0",unless = "#result==null")
    @Cacheable(key = "#id",condition = "#id>0",unless = "#result==null")
    public Role findById(Integer id) {
        return roleMapper.selectByPrimaryKey(id);
    }
  
    @Cacheable(key ="#root.method.getName()")//直接引用mehtodname异常
    @Override
    public R findAllRole() {
        List<Role> roleList = roleMapper.findAll();
        return R.ok(roleList);
    }
}
3.2:@CacheEvict注解

@CacheEvict:删除缓存的注解,这对删除旧的数据和无用的数据是非常有用的。这里还多了一个参数(allEntries),设置allEntries=true时,可以对整个条目进行批量删除

  /**
     * .@CacheEvict 缓存清除
     *  key:指定要清除的数据
     */
    @Override
    @CacheEvict(key = "#id")
    public Integer delete(Integer id) {
        return roleMapper.deleteByPrimaryKey(id);
    }
3.3:@CachePut注解

@CachePut:当需要更新缓存而不干扰方法的运行时 ,可以使用该注解。也就是说,始终执行该方法,并将结果放入缓存

本质上说,如果存在对应的缓存,则更新覆盖,不存在则添加;

/**
     * .@CachePut既调用方法、又更新数据,达到同步更新缓存
     * <p>
     * 运行时机:
     * 1、先调用目标方法 ★★★
     * 2、将目标方法的结果缓存起来★★★
     * 条件:存取Id的key要保持一致
     *     key = "#role.id"     传入员工的Id
     *     key = "#result.id"   使用返回员工的Id
     * 注意: @Cacheable不能使用#result
     *      因为 @Cacheable在目标方法执行之前需要得到这个key,所以不能用#result
     */
@Override
@CachePut(key = "#result.id")//更新或者添加缓存---》有则更新,无则添加
public Role update(Role role) {
  roleMapper.updateByPrimaryKey(role);
  return role;
}
3.4:@Caching注释

在使用缓存的时候,有可能会同时进行更新和删除,会出现同时使用多个注解的情况.而@Caching可以实现,对于复杂的缓存策略,我们可借助SpEL实现;

Spring Cache提供了一些供我们使用的SpEL上下文数据,下表直接摘自Spring官方文档:

 /**
     * .@Caching 定义复杂缓存规则
     */
    @Override
    @Caching(
            cacheable = {
                    @Cacheable(key = "#role.rolename")
               
            },
            put = {
                    @CachePut(key = "#role.id"),
                    @CachePut(key = "#role.rolecode")
            },
            evict = {
                    @CacheEvict(key = "8")
            }
    )
    public R add(Role role) {
//        role.setId(null);
        try {
            roleMapper.insert(role);
        } catch (Exception e) {
            return R.error();
        }
        return R.ok(role.getId());
    }
3.5:注解小结

对于缓存声明,spring的缓存提供了一组java注解:

  • @Cacheable
  • 功能:触发缓存写入,如果缓存中没有,查询数据库,存储缓存,返回结果,如果缓存中有,直接返回结果
  • 应用:查询数据库方法,且查询的数据时热点数据
  • @CacheEvict
  • 功能:触发缓存清除
  • 应用:删除或修改数据库方法
  • @CachePut
  • 功能:缓存写入(不会影响到方法的运行)。有则更新,无则添加
  • 应用:新增到数据库方法
  • @Caching
  • 功能:重新组合要应用于方法的多个缓存操作
  • 应用:上面的注解的组合使用
  • @CacheConfig(cacheNames = "xxx")
  • 功能:可以提取公共的缓存key的前缀,一般是业务的前缀
  • 应用:作用在类之上
相关文章
|
7月前
|
缓存 NoSQL Java
SpringCache通用缓存学习
SpringCache通用缓存学习
|
存储 缓存 NoSQL
分布式缓存Redis击穿、雪崩、穿透面试题+SpringCache解决方案
分布式缓存Redis击穿、雪崩、穿透面试题+SpringCache解决方案
202 0
|
缓存 NoSQL Java
SpringCache通用缓存学习(二)
SpringCache通用缓存学习
187 2
SpringCache通用缓存学习(二)
|
SQL 缓存 NoSQL
SpringCache通用缓存学习(一)
SpringCache通用缓存学习
211 2
SpringCache通用缓存学习(一)
|
缓存 NoSQL Java
基于注解实现缓存的框架 -- SpringCache
Spring Cache是一个框架,实现了基于注解的缓存功能,只需要简单地加一个注解,就能实现缓存功能,大大简化我们在业务中操作缓存的代码。
基于注解实现缓存的框架 -- SpringCache
|
缓存 JSON NoSQL
[Springboot]SpringCache + Redis实现数据缓存
本文实现了SpringCache + Redis的集中式缓存,方便大家对学习了解缓存的使用。 本文实现: SpringCache + Redis的组合 通过配置文件实现了自定义key过期时间;key命名方式;value序列化方式 实现本文代码的前提: 已有一个可以运行的Springboot项目,实现了简单的CRUD功能
241 0
|
SQL 缓存 NoSQL
SpringCache通用缓存学习
Spring Cache是一个框架,实现了基于注解的缓存功能,只需要简单地加一个注解,就能实现缓存功能,大大简化我们在业务中操作缓存的代码。 Spring Cache只是提供了一层抽象,底层可以切换不同的cache实现。具体就是通过CacheManager接口来统一不同的缓存技术。CacheManager是Spring提供的各种缓存技术抽象接口。
150 0
SpringCache通用缓存学习
|
1天前
|
存储 缓存 NoSQL
解决Redis缓存数据类型丢失问题
解决Redis缓存数据类型丢失问题
109 85
|
2月前
|
消息中间件 缓存 NoSQL
Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。
【10月更文挑战第4天】Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。随着数据增长,有时需要将 Redis 数据导出以进行分析、备份或迁移。本文详细介绍几种导出方法:1)使用 Redis 命令与重定向;2)利用 Redis 的 RDB 和 AOF 持久化功能;3)借助第三方工具如 `redis-dump`。每种方法均附有示例代码,帮助你轻松完成数据导出任务。无论数据量大小,总有一款适合你。
78 6
|
1月前
|
缓存 NoSQL 关系型数据库
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
本文详解缓存雪崩、缓存穿透、缓存并发及缓存预热等问题,提供高可用解决方案,帮助你在大厂面试和实际工作中应对这些常见并发场景。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题