当前位置:

首页 > 编程开发 > SpringBoot项目中怎么使用缓存Cache

SpringBoot项目中怎么使用缓存Cache

前言缓存可以通过将经常访问的数据存储在内存中,减少底层数据源如数据库的压力,从而有效提高系统的性能和稳定性。我想大家的项目中或多或少都有使用过,我们项目也不例外,但是最近在review公司的代码的时候写的很蠢且low,大致写法如下:publicUsergetById(Stringid){Useruser=cache.getUser();if(user!=null){returnuser;}//从数据库获取user=loadFromDB(id);cahce.put(id,user);returnuser;}

本文目录

    前言

    缓存可以通过将经常访问的数据存储在内存中,减少底层数据源如数据库的压力,从而有效提高系统的性能和稳定性。我想大家的项目中或多或少都有使用过,我们项目也不例外,但是最近在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
    @EnableCaching
    public class SpringCacheApp {
    
        public static void main(String[] args) {
            SpringApplication.run(Cache.class, args);
        }
    }

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

    自定义缓存管理器

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

    1.添加依赖

    
      org.springframework.boot
      spring-boot-starter-data-redis
    

    2.配置Redis缓存管理器

    @Configuration
    @EnableCaching
    public 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:缓存数据库查询的结果。

    @Service
    public 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 注解一般用于更新缓存数据,相当于缓存使用的是写模式中的双写模式。

    @Service
    public 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

    @Service
    public 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 时失效两个缓存。

    @Service
    public 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缓存中移除缓存结果。

    @Service
    public 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注解将结果添加到 myCache、myOtherCache 和 myThirdCache 缓存中。Spring 还将根据@Cacheable注解检查结果是否已缓存在 myFourthCache 和 myFifthCache 缓存中。如果结果尚未缓存,Spring 会将结果缓存在适当的缓存中。如果结果已经被缓存,Spring 将返回缓存的结果,而不是再次执行该方法。

    @Service
    public 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"})
    @Service
    public 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

    • condition作用:指定缓存的条件(满足什么条件才缓存),可用 SpEL 表达式(如 #id>0,表示当入参 id 大于 0 时才缓存)

    • unless作用 : 否定缓存,即满足 unless 指定的条件时,方法的结果不进行缓存,使用 unless 时可以在调用的方法获取到结果之后再进行判断(如 #result == null,表示如果结果为 null 时不缓存)

    //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);
    }

    清理全部缓存

    通过allEntries、beforeInvocation属性可以来清除全部缓存数据,不过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 支持多种缓存提供程序,包括 Ehcache、Hazelcast 和 Redis。

    • 使用缓存时请注意潜在的线程安全问题。对缓存的并发访问可能会导致数据不一致或不正确,因此选择线程安全的缓存提供程序并在必要时使用适当的同步机制非常重要。

    • 避免过度缓存。缓存对于提高性能很有用,但过多的缓存实际上会消耗宝贵的内存资源,从而损害性能。在缓存频繁使用的数据和允许垃圾收集不常用的数据之间取得平衡很重要。

    • 使用适当的缓存逐出策略。使用缓存时,重要的是定义适当的缓存逐出策略以确保在必要时从缓存中删除旧的或陈旧的数据。

    • 使用适当的缓存键设计。缓存键对于每个数据项都应该是唯一的,并且应该考虑可能影响缓存数据的任何相关参数,例如用户 ID、时间或位置。

    • 常规数据(读多写少、即时性与一致性要求不高的数据)完全可以使用 Spring Cache,至于写模式下缓存数据一致性问题的解决,只要缓存数据有设置过期时间就足够了。

    • 特殊数据(读多写多、即时性与一致性要求非常高的数据),不能使用 Spring Cache,建议考虑特殊的设计(例如使用 Cancal 中间件等)。

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发
    相关文章 更多
    容器内存占用之系统cache介绍
    容器内存占用之系统cache介绍

    缘起 监控上看到容器内存已经撑爆了,但进去一查,进程列表里根本找不到哪个进程在吃内存。用 awk 把容器所有进程的 RSS 加起来,算出来的值离内存上限还差一大截。这到底是怎么回事? 分析 第一个念头:难道是 docker stats 算错了? 进 /sys/fs/cgroup/memory/doc

    springBoot项目常用目录有哪些
    springBoot项目常用目录有哪些

    springBoot项目常用目录springBoot项目的目录结构及名规范介绍基于SpringBoot开发时的目录结构及命名规范,通过介绍能够为你解决,在实际项目中如何规划目录结构?如何命名目录更规范?各个目录分别代表什么含义?等三个问题。目录说明servicex//项目名|-admin-ui//管理服务前端代码(一般将UI和SERVICE放到一个工程中,便于管理)|-servicex-auth//模块1|-servicex-common//模块2|-servicex-gateway//模块3|-serv

    学习如何配置NGINX的反向代理缓存
    学习如何配置NGINX的反向代理缓存

    以下是nginx反向代理缓存的教程:安装nginx:sudoaptupdatesudoaptinstallnginx配置反向代理:打开nginx配置文件:sudonano/etc/nginx/nginx.conf在http块中添加以下配置来启用缓存:http{...proxy_cache_path/var/cache/nginxlevels=1:2keys_zone=my_cache:10mmax_size=10ginactive=60muse_temp_path=off;proxy_cache_key"

    了解 Alibaba Cloud Cache 缓存技术
    了解 Alibaba Cloud Cache 缓存技术

    随着互联网规模和业务复杂度的不断扩大,高并发、高访问量等问题成为了互联网企业数据存储和处理的难点。而缓存技术正是为了解决这些问题而诞生的。在众多的缓存技术中,阿里云的AlibabaCloudCache(简称ACC)无疑是一个强大、安全、高效的缓存技术。什么是AlibabaCloudCache缓存技术?首先,我们来看看阿里云官网对于Aliba

    解析SpringBoot和SpringMVC之间的异同
    解析SpringBoot和SpringMVC之间的异同

    解析SpringBoot和SpringMVC之间的异同SpringBoot和SpringMVC是Java领域中非常重要的开发框架。虽然它们都属于Spring框架的一部分,但是在使用和功能上有一些明显的区别。本文将对SpringBoot和SpringMVC进行比较,解析它们之间的异同。首先,让我们来了解一下SpringBoot。SpringBo

    探索SpringCloud和SpringBoot在微服务领域的不同应用方式
    探索SpringCloud和SpringBoot在微服务领域的不同应用方式

    近年来,随着云计算和分布式架构的兴起,微服务架构的应用越来越广泛。而SpringCloud和SpringBoot作为Java开发中的两个重要框架,对于微服务的实现起到了重要的作用。然而,很多人对于它们在微服务领域的不同应用方式还存在一定的疑惑。本文将从不同的角度探索SpringCloud和SpringBoot在微服务中的应用方式。首先,我们来了解一下Spri

    SpringBoot和SpringMVC有何区别?
    SpringBoot和SpringMVC有何区别?

    SpringBoot与SpringMVC的不同之处在哪里?SpringBoot和SpringMVC是两个非常流行的Java开发框架,用于构建Web应用程序。尽管它们经常分别被使用,但它们之间的不同之处也是很明显的。首先,SpringBoot可以被看作是一个Spring框架的扩展或者增强版。它旨在简化Spring应用程序的初始化和配置过程,以帮助开发人

    比较SpringBoot和SpringMVC的异同
    比较SpringBoot和SpringMVC的异同

    SpringBoot和SpringMVC都是Java开发中常用的框架,但它们之间有一些明显的差异。本文将探究这两个框架的特点和用途,并对它们的差异进行比较。首先,我们来了解一下SpringBoot。SpringBoot是由Pivotal团队开发的,它旨在简化基于Spring框架的应用程序的创建和部署。它提供了一种快速、轻量级的方式来构建独立的、可执行

    SpringBoot与SpringMVC的不同点是什么?
    SpringBoot与SpringMVC的不同点是什么?

    SpringBoot和SpringMVC是Java开发中常用的两个框架,它们都是由Spring框架所提供的,但在功能和使用方式上有着一些区别。本文将分别介绍SpringBoot和SpringMVC的特点和区别。一、SpringBoot的特点:简化配置:SpringBoot通过约定优于配置的原则,大大简化了项目的配置过程。它可以自动配置项目所需要的参数,开发人

    比较和选择指南:SpringCloud与SpringBoot的功能比较
    比较和选择指南:SpringCloud与SpringBoot的功能比较

    SpringCloud和SpringBoot是目前Java领域中最热门的开源框架,它们分别提供了一套完善的微服务架构和快速构建应用程序的解决方案。本文将对它们的功能进行比较,并给出选择指南,以帮助读者了解它们的优势和适用场景。SpringBoot是一个用于开发Java应用程序的框架,它提供了一个简化的开发流程,集成了大量常用的功能和组件,减少了开发者的工作量

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程
    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    Aperty macOS版
    Aperty macOS版
    macOS

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    PixTV 网页版
    PixTV 网页版
    Windows

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。