文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

SpringBoot项目中怎么使用缓存Cache

2023-07-06 00:08

关注

本文小编为大家详细介绍“SpringBoot项目中怎么使用缓存Cache”,内容详细,步骤清晰,细节处理妥当,希望这篇“SpringBoot项目中怎么使用缓存Cache”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。

前言

缓存可以通过将经常访问的数据存储在内存中,减少底层数据源如数据库的压力,从而有效提高系统的性能和稳定性。我想大家的项目中或多或少都有使用过,我们项目也不例外,但是最近在review公司的代码的时候写的很蠢且low, 大致写法如下:

public User getById(String id) {User user = cache.getUser();    if(user != null) {        return user;    }    // 从数据库获取    user = loadFromDB(id);    cahce.put(id, user);return user;}

其实Spring Boot 提供了强大的缓存抽象,可以轻松地向您的应用程序添加缓存。本文就讲讲如何使用 Spring 提供的不同缓存注解实现缓存的最佳实践。

启用缓存@EnableCaching

现在大部分项目都是是SpringBoot项目,我们可以在启动类添加注解@EnableCaching来开启缓存功能。

@SpringBootApplication@EnableCachingpublic class SpringCacheApp {    public static void main(String[] args) {        SpringApplication.run(Cache.class, args);    }}

既然要能使用缓存,就需要有一个缓存管理器Bean,默认情况下,@EnableCaching 将注册一个ConcurrentMapCacheManager的Bean,不需要单独的 bean 声明。ConcurrentMapCacheManager将值存储在ConcurrentHashMap的实例中,这是缓存机制的最简单的线程安全实现。

自定义缓存管理器

默认的缓存管理器并不能满足需求,因为她是存储在jvm内存中的,那么如何存储到redis中呢?这时候需要添加自定义的缓存管理器。

添加依赖

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

配置Redis缓存管理器

@Configuration@EnableCachingpublic class CacheConfig {    @Bean    public RedisConnectionFactory redisConnectionFactory() {        return new LettuceConnectionFactory();    }    @Bean    public CacheManager cacheManager() {        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()            .disableCachingNullValues()            .serializeValuesWith(SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));        RedisCacheManager redisCacheManager = RedisCacheManager.builder(redisConnectionFactory())            .cacheDefaults(redisCacheConfiguration)            .build();        return redisCacheManager;    }}

现在有了缓存管理器以后,我们如何在业务层面操作缓存呢?

我们可以使用@Cacheable@CachePut 或@CacheEvict 注解来操作缓存了。

@Cacheable

该注解可以将方法运行的结果进行缓存,在缓存时效内再次调用该方法时不会调用方法本身,而是直接从缓存获取结果并返回给调用方。

SpringBoot项目中怎么使用缓存Cache

例子1:缓存数据库查询的结果。

@Servicepublic class MyService {    @Autowired    private MyRepository repository;    @Cacheable(value = "myCache", key = "#id")    public MyEntity getEntityById(Long id) {        return repository.findById(id).orElse(null);    }}

在此示例中,@Cacheable 注解用于缓存 getEntityById()方法的结果,该方法根据其 ID 从数据库中检索 MyEntity 对象。

但是如果我们更新数据呢?旧数据仍然在缓存中?

@CachePut

然后@CachePut 出来了, 与 @Cacheable 注解不同的是使用 @CachePut 注解标注的方法,在执行前不会去检查缓存中是否存在之前执行过的结果,而是每次都会执行该方法,并将执行结果以键值对的形式写入指定的缓存中。@CachePut 注解一般用于更新缓存数据,相当于缓存使用的是写模式中的双写模式。

@Servicepublic class MyService {    @Autowired    private MyRepository repository;    @CachePut(value = "myCache", key = "#entity.id")    public void saveEntity(MyEntity entity) {        repository.save(entity);    }}

@CacheEvict

标注了 @CacheEvict 注解的方法在被调用时,会从缓存中移除已存储的数据。@CacheEvict 注解一般用于删除缓存数据,相当于缓存使用的是写模式中的失效模式。

SpringBoot项目中怎么使用缓存Cache

@Servicepublic class MyService {    @Autowired    private MyRepository repository;     @CacheEvict(value = "myCache", key = "#id")    public void deleteEntityById(Long id) {        repository.deleteById(id);    }}

@Caching

@Caching 注解用于在一个方法或者类上,同时指定多个 Spring Cache 相关的注解。

SpringBoot项目中怎么使用缓存Cache

例子1:@Caching注解中的evict属性指定在调用方法 saveEntity 时失效两个缓存。

@Servicepublic class MyService {    @Autowired    private MyRepository repository;    @Cacheable(value = "myCache", key = "#id")    public MyEntity getEntityById(Long id) {        return repository.findById(id).orElse(null);    }    @Caching(evict = {        @CacheEvict(value = "myCache", key = "#entity.id"),        @CacheEvict(value = "otherCache", key = "#entity.id")    })    public void saveEntity(MyEntity entity) {        repository.save(entity);    }}

例子2:调用getEntityById方法时,Spring会先检查结果是否已经缓存在myCache缓存中。如果是,Spring 将返回缓存的结果而不是执行该方法。如果结果尚未缓存,Spring 将执行该方法并将结果缓存在 myCache 缓存中。方法执行后,Spring会根据@CacheEvict注解从otherCache缓存中移除缓存结果。

@Servicepublic class MyService {    @Caching(        cacheable = {            @Cacheable(value = "myCache", key = "#id")        },        evict = {            @CacheEvict(value = "otherCache", key = "#id")        }    )    public MyEntity getEntityById(Long id) {        return repository.findById(id).orElse(null);    }}

例子3:当调用saveData方法时,Spring会根据@CacheEvict注解先从otherCache缓存中移除数据。然后,Spring 将执行该方法并将结果保存到数据库或外部 API。

方法执行后,Spring 会根据@CachePut注解将结果添加到 myCachemyOtherCache 和 myThirdCache 缓存中。Spring 还将根据@Cacheable注解检查结果是否已缓存在 myFourthCache 和 myFifthCache 缓存中。如果结果尚未缓存,Spring 会将结果缓存在适当的缓存中。如果结果已经被缓存,Spring 将返回缓存的结果,而不是再次执行该方法。

@Servicepublic class MyService {    @Caching(        put = {            @CachePut(value = "myCache", key = "#result.id"),            @CachePut(value = "myOtherCache", key = "#result.id"),            @CachePut(value = "myThirdCache", key = "#result.name")        },        evict = {            @CacheEvict(value = "otherCache", key = "#id")        },        cacheable = {            @Cacheable(value = "myFourthCache", key = "#id"),            @Cacheable(value = "myFifthCache", key = "#result.id")        }    )    public MyEntity saveData(Long id, String name) {        // Code to save data to a database or external API        MyEntity entity = new MyEntity(id, name);        return entity;    }}

@CacheConfig

通过@CacheConfig 注解,我们可以将一些缓存配置简化到类级别的一个地方,这样我们就不必多次声明相关值:

@CacheConfig(cacheNames={"myCache"})@Servicepublic class MyService {    @Autowired    private MyRepository repository;    @Cacheable(key = "#id")    public MyEntity getEntityById(Long id) {        return repository.findById(id).orElse(null);    }    @CachePut(key = "#entity.id")    public void saveEntity(MyEntity entity) {        repository.save(entity);    }    @CacheEvict(key = "#id")    public void deleteEntityById(Long id) {        repository.deleteById(id);    }}

Condition & Unless

//when id >10, the @CachePut works. @CachePut(key = "#entity.id", condition="#entity.id > 10")public void saveEntity(MyEntity entity) {repository.save(entity);}//when result != null, the @CachePut works.@CachePut(key = "#id", condition="#result == null")public void saveEntity1(MyEntity entity) {repository.save(entity);}

清理全部缓存

通过allEntriesbeforeInvocation属性可以来清除全部缓存数据,不过allEntries是方法调用后清理,beforeInvocation是方法调用前清理。

//方法调用完成之后,清理所有缓存@CacheEvict(value="myCache",allEntries=true)public void delectAll() {    repository.deleteAll();}//方法调用之前,清除所有缓存@CacheEvict(value="myCache",beforeInvocation=true)public void delectAll() {    repository.deleteAll();}

SpEL表达式

Spring Cache注解中频繁用到SpEL表达式,那么具体如何使用呢?

SpEL 表达式的语法

SpringBoot项目中怎么使用缓存Cache

Spring Cache可用的变量

SpringBoot项目中怎么使用缓存Cache

最佳实践

通过Spring缓存注解可以快速优雅地在我们项目中实现缓存的操作,但是在双写模式或者失效模式下,可能会出现缓存数据一致性问题(读取到脏数据),Spring Cache 暂时没办法解决。最后我们再总结下Spring Cache使用的一些最佳实践。

读到这里,这篇“SpringBoot项目中怎么使用缓存Cache”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注编程网行业资讯频道。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯