SpringBoot的缓存管理

news2024/9/29 7:18:53

缓存是分布式系统中的重要组件,主要解决数据库数据的高并发访问问题。在实际开发中,尤其是用户 访问量较大的网站,为了提高服务器访问性能、减少数据库的访问压力、提高用户体验,使用缓存显得 尤为重要。Spring Boot对缓存提供了良好的支持

默认缓存管理

        Spring框架支持透明地向应用程序添加缓存并对缓存进行管理,其管理缓存的核心是将缓存应用于操作 数据的方法中,从而减少操作数据的次数,同时不会对程序本身造成任何干扰。Spring Boot继承了Spring框架的缓存管理功能,通过使用@EnableCaching注解开启基于注解的缓存支持,Spring Boot可以启动缓存管理的自动化配置

Spring Boot默认缓存体验

1.使用@EnableCaching注解开启基于注解的缓存支持,该注解通常会添加在项目启动类上

 2.使用@Cacheable注解对数据操作方法进行缓存管理。将@Cacheable注解标注在CommentService类 的查询方法上,对查询结果进行缓存

 这样我们就不会每次访问的时候都去数据库进行查询,大大节省了效率,只要查的数据一致,无论查多少次都只会进行一次查询,然后保存到缓存区,之后每次查询的数据都是从缓存中获取的

Spring Boot缓存注解介绍

        1.@EnableCaching注解:@EnableCaching是由Spring框架提供的,Spring Boot框架对该注解进行了继承,该注解需要配置在类上(在Spring Boot中,通常配置在项目启动类上),用于开启基于注解的缓存支持。

        2.@Cacheable注解:@Cacheable注解也是由Spring框架提供的,可以作用于类或方法(通常用在数据查询方法上),用于 对方法的查询结果进行缓存存储。@Cacheable注解的执行顺序是,先进行缓存查询,如果为空则进行 方法查询,并将结果进行缓存;如果缓存中有数据,不进行方法查询,而是直接使用缓存数据

          cacheNames  缓存空间名                unless     条件成立则不缓存          key    指定id,默认为形参的具体指   

          #result    获取结果

        3.@CachePut注解:@CachePut注解是由Spring框架提供的,可以作用于类或方法(通常用在数据更新方法上),该注解的 作用是更新缓存数据。@CachePut注解的执行顺序是,先进行方法调用,然后将方法结果更新到缓存 中

        4.@CacheEvict注解;

@CacheEvict注解是由Spring框架提供的,可以作用于类或方法(通常用在数据删除方法上),该注解 的作用是删除缓存数据。@CacheEvict注解的默认执行顺序是,先进行方法调用,然后清除缓存。 @CacheEvict注解提供了多个属性,这些属性与@Cacheable注解的属性基本相同。 除此之外,@CacheEvict注解额外提供了两个特殊属性allEntries和beforeInvocation,其说明如下

                 1)allEntries属性:allEntries属性表示是否清除指定缓存空间中的所有缓存数据,默认值为false(即默认只删除指定key对应的缓存数据)。例如@CacheEvict(cacheNames="comment",allEntries= true)表示方法执行后会删除 缓存空间comment中所有的数据

                  2)beforeInvocation属性:beforeInvocation属性表示是否在方法执行之前进行缓存清除,默认值为false(即默认在执行方法后再 进行领存清除)例如@CacheEvict(cacheNames="comment",beforeInvocation=true)表示会在方法执 行之前进行缓存清除。

需要注意的是,如果将@CacheEvict注解的beforeInvocation属性设置为true,会存在一定的弊端。例 如在进行数据删除的方法中发生了异常,这会导致实际数据并没有被删除,但是缓存数据却被提前清除了

        5.@Caching注解:如果处理复杂规则的数据缓存可以使用@Caching注解,该注解作用于类或者方法上。@Caching注解包 含三个属性cacheable、put和evict,它们的作用等同于@Cacheable、@CachePut和@CacheEvict。

                          例子:@Caching(cacheable = {@Cacheable(cacheNames = "comment", key = "#comment_id")},put = {@CachePut(cacheNames = "comment", key = "#result.author")})

        6.@CacheConfig注解:@CacheConfig注解作用于类,主要用于统筹管理类中所有使用@Cacheable、@CachePut和@CacheEvict注解标注的方法中的公共属性,这些公共属性包括 cacheNames,keyGenerator,cacheManager和cacheResolver。

基于注解的Redis缓存实现

             1.添加pom文件

        

<!-- 引入整合Redis缓存的依赖启动器 -->

<dependency>

    <groupId>org.springframework.boot</groupId>

    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

         2. 在核心配置文件application.properties中添加Redis服务的连接配置

       

# Redis服务器地址

spring.redis.host=192.168.40.100

# Redis服务器连接端口

spring.redis.port=6379

# Redis服务器连接密码(默认为空)

spring.redis.password=

         3.在对实体类对象进行缓存存储时必须先实现 序列化,让实体类实现Serializable接口,否则会出现缓存异 常,导致程序无法正常执行

           4.编写实体类CommentServiceImpl

import com.example.springboot_cache.domain.Comment;
import com.example.springboot_cache.repository.CommentRepository;
import com.example.springboot_cache.service.CommentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.*;
import org.springframework.stereotype.Service;

import java.util.Optional;
@CacheConfig(cacheNames = "comment") //公用的属性可以在这个注解里面指定
@Service
public class CommentServiceImpl implements CommentService {

    @Autowired
    private CommentRepository commentRepository;

    @Override 
    @Cacheable(unless = "#result==null")
    public Comment findById(int comment_id) {
        Optional<Comment> optional  = commentRepository.findById(comment_id);
        if(optional.isPresent()){
            return optional.get();//获取optional中的comment对象
        }
        return null;
    }

    @Override 
    @CachePut(key = "#result.cid")
    public Comment updateComment(Comment c) {
        int i = commentRepository.updateComment(c.getAuthor(), c.getCid());
        Optional<Comment> cc = commentRepository.findById(c.getCid());

       if(cc.isPresent()){
           return  cc.get();
       }
        return null;
    }

    @Override
    @CacheEvict()
    public void deleteComment(Integer cid) {
        Comment comment = new Comment();
        comment.setCid(cid);
        commentRepository.delete(comment);
    } 
}

          5.编写完成后重启项目,然后访问刚刚的接口,可以看到也实现了缓存,数据存储在Redis中

基于API的Redis缓存实现

        1.编写实体类 APICommentServiceImpl

import com.example.springboot_cache.domain.Comment;
import com.example.springboot_cache.repository.CommentRepository;
import com.example.springboot_cache.service.CommentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Optional;
import java.util.concurrent.TimeUnit;

@Service
public class APICommentServiceImpl implements CommentService {

    @Autowired
    private CommentRepository commentRepository;
    @Autowired  //简化了Redis操作的模板类,底层封装了Jedis
    private RedisTemplate redisTemplate;

    @Override//将数据存到redis中,如果存在则直接返回
    public Comment findById(int comment_id) {
        Object o = redisTemplate.opsForValue().get("comment_" + comment_id);
        if(o==null){
            Optional<Comment> optional  = commentRepository.findById(comment_id);
            if(optional.isPresent()){
                Comment comment = optional.get();//获取optional中的comment对象
            //   redisTemplate.opsForValue().set("comment_"+comment_id,comment);
                redisTemplate.opsForValue().set("comment_"+comment_id,comment,1, TimeUnit.DAYS);
                return comment;
            }else {
                return null;
            }
        }else {
            return (Comment) o;
        }
    }


    @Override
    public Comment updateComment(Comment c) {
        int i = commentRepository.updateComment(c.getAuthor(), c.getCid());
        Optional<Comment> cc = commentRepository.findById(c.getCid());
        if(cc.isPresent()){
           return  cc.get();
       }

        redisTemplate.opsForValue().set("comment_"+c.getCid(),cc.get());


        return null;
    }

    @Override
    public void deleteComment(Integer cid) {
        Comment comment = new Comment();
        comment.setCid(cid);
        commentRepository.delete(comment);
        redisTemplate.delete("comment_"+cid);
    }
}

                2.编写控制层类APICommentController

import com.example.springboot_cache.domain.Comment;
import com.example.springboot_cache.service.CommentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("api")
public class APICommentController {
    @Autowired
    private  CommentService  commentService;



    @GetMapping("/get/{cid}")
    public Comment findById(@PathVariable Integer cid){
           return commentService.findById(cid);
    }

    @GetMapping("/update/{cid}/{author}")
    public Comment updateComment(@PathVariable("author") String author,@PathVariable("cid") int cid){
        Comment comment = commentService.findById(cid);
        comment.setAuthor(author);

        Comment c = commentService.updateComment(comment);
        return c;
    }


    @DeleteMapping("/delete/{cid}")
    public void deleteComment(@PathVariable Integer cid){
        commentService.deleteComment( cid);
    }

}

        3.编写完成后重启之间要先把CommentServiceImpl的@Service注释掉

 

 也是只在数据库查询一次,之后就再Redis缓存中查询,但是我们看到的缓存数据是二进制的乱码,我们并看不到,所以就需要我们的配置类来把存储的数据转化JSON格式

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.*;

import java.time.Duration;

@Configuration
public class RedisConfig   {
     @Bean//api乱码解决
    public RedisTemplate<Object,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
        //Redis模板类的连接工厂
        RedisTemplate<Object,Object> redisTemplate =new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        //使用JSON格式序列化对象                                                       将对象的数据缓存为ket,value的结构
        Jackson2JsonRedisSerializer jackson2  = new Jackson2JsonRedisSerializer<>(Object.class);

        //解决查询缓存转换异常的问题
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2.setObjectMapper(om);
        //设置redisTemplate模板的序列化数据方式
        redisTemplate.setDefaultSerializer(jackson2);


        return redisTemplate;
    }


    @Bean  //注解乱码解决    返回值表示一个Redis缓存管理器对象,通过这对象来管理和配置基于注解式开发缓存的数据进行序列化转化
    public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory){
        Jackson2JsonRedisSerializer json =new Jackson2JsonRedisSerializer<>(Object.class);//设置value的序列化方式
        RedisSerializer<String>   strSerializer =new StringRedisSerializer();//设置key的序列化方式





        //解决查询缓存转换异常的问题
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        json.setObjectMapper(om);

        //创建 RedisCacheConfiguration 对象
        RedisCacheConfiguration configuration =RedisCacheConfiguration.defaultCacheConfig()
                                                 .entryTtl(Duration.ofDays(1))//设置存活时间为1天
                                                 .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(strSerializer))//指定key进行序列化
                                                 .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(json))
                                                   .disableCachingNullValues();//null值不允许参与序列化操作

        //RedisCacheManager对象                                                    设置默认的缓存
        RedisCacheManager man = RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(configuration).build();

        return man;
    }
}

           配置完成后重新查询,然后在官网下载Redis的软件工具,将查看的格式改为JSON我们就可以查询到不是二进制乱码的数据

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/711729.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

js将后台返回的数据转化为树形结构(扁平数组转树状结构)

前言 做项目使常遇到需要将后台返回的数据&#xff0c;转换为树状结构给用户展现&#xff0c;例如&#xff1a; 这也是前端面试常考的算法题&#xff0c;一起来检测一下吧。 步骤 准备一个空的树对象。遍历列表中的每个元素。对于每个元素&#xff0c;根据该元素的父级ID找到…

Linux常用命令——fdisk命令

在线Linux命令查询工具 fdisk 查看磁盘使用情况和磁盘分区 补充说明 fdisk命令用于观察硬盘实体使用情况&#xff0c;也可对硬盘分区。它采用传统的问答式界面&#xff0c;而非类似DOS fdisk的cfdisk互动式操作界面&#xff0c;因此在使用上较为不便&#xff0c;但功能却丝…

ERP重构-SLA子分类账-分布式实现方案

背景 ERP中的GL总账模块&#xff0c;明细数据来源于各个业务模块如库存、成本、应收、应付、费控、资产等&#xff0c;统称为子模块&#xff0c;生成的账叫做子分类账。然而记账的业务逻辑各式各样&#xff0c;但是最终输出都是来源、类型、期间、科目、借贷金额等等关键信息。…

Java-数据结构(二)-Map:HashMap、TreeMap、LinkedHashMap

目录 一、 引言二、问题2.1 什么是Map2.2 使用Map的好处2.3 Map的底层原理2.4 Key和Value的含义2.5 Key值为什么不能重复2.6 Key值和Hash的关系 三、 HashMap3.1 初始化HashMap3.2 添加和获取元素3.3 遍历HashMap3.4 删除元素3.5实现原理①HashMap的put()方法②HashMap的get()方…

【海量数据挖掘/数据分析】 之 贝叶斯分类算法(朴素贝叶斯分类、贝叶斯分类计算流程、拉普拉斯修正、贝叶斯分类实例计算)

【海量数据挖掘/数据分析】 之 贝叶斯分类算法&#xff08;朴素贝叶斯分类、贝叶斯分类计算流程、拉普拉斯修正、贝叶斯分类实例计算&#xff09; 目录 【海量数据挖掘/数据分析】 之 贝叶斯分类算法&#xff08;朴素贝叶斯分类、贝叶斯分类计算流程、拉普拉斯修正、贝叶斯分类…

无java环境运行jar

1、编写简单java程序。 例&#xff1a; public static void main(String[] args) {if(args.length>0)System.out.println("Params is&#xff1a;"args[0]);System.out.println("Hello word ! I am demo&#xff0c;&#xff0c;&#xff0c;&#xff0c…

软考高级网规考试笔记(涉及表格用图片代替_9万字左右)

作者&#xff1a;BSXY_19计科_陈永跃_23年7月更 BSXY_信息学院_v:CwJp0403 注&#xff1a;未经允许禁止转发任何内容 笔记说明&#xff1a; 目前还只有笔记&#xff0c;其他资源将会在近期更新&#xff0c;&#xff08;笔记5.5即可&#xff0c;不诚勿加可以去其他地方自找找看&…

Quartz任务调度笔记

一、概念 1.1简介 Quzrtz是OpenSymphony开源组织在Job scheduling领域的开源项目 特点&#xff1a;Quartz具有丰富特性的"任务调度库"&#xff0c;能够集成于任何的Java应用&#xff0c;小到独立的应用&#xff0c;大到电子商业系统。quartz能够创建亦简单亦复杂的调…

DAY35:贪心算法(二)分发饼干+摆动序列

文章目录 455.分发饼干思路两个for循环嵌套的写法为什么这种写法必须要有visited数组debug测试逻辑问题&#xff1a;没有进行计数逻辑问题&#xff1a;找到了result3个孩子 一层for循环的写法为什么这种写法一定要把小孩数组放在外面 376.摆动序列&#xff08;逻辑问题&#xf…

02_04实时调度类及SMP多核处理器的实时操作系统体系结构

上一篇文章说的是普通进程的调度但同时还有实时进程在linux上面进行运行 这边来看看实时进程在linux里面怎么调度 同时linux操作系统对实时任务的处理方式和设计思想 实时调度类 Linux进程分为两大类:实时进程和普通进程。 实时进程与普通进程根本不同之处&#xff0c;如果系…

ModuleNotFoundError: No module named ‘transformers_modules.chatglm2-6b‘解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

青少年机器人技术一级核心知识点:机械结构及模型(四)

随着科技的不断进步&#xff0c;机器人技术已经成为了一个重要的领域。在这个领域中&#xff0c;机械结构是机器人设计中至关重要的一部分&#xff0c;它决定了机器人的形态、运动方式和工作效率。对于青少年机器人爱好者来说&#xff0c;了解机械结构的基础知识&#xff0c;掌…

LabVIEW大模拟数据解决方案

LabVIEW大模拟数据解决方案 比亚迪汽车对于在动力总成标定和控制部门工作的400多名工程师来说&#xff0c;这种投资包括实现NI的新战略和解决方案&#xff0c;以更好地捕获和管理大量的原始测试数据&#xff0c;在车辆上市前做出更明智的决策。 因为能够更好地获取更优质的数…

Go语言开发者的Apache Arrow使用指南:内存管理

如果你看了上一篇《Go语言开发者的Apache Arrow使用指南&#xff1a;数据类型》[1]中的诸多Go操作arrow的代码示例&#xff0c;你很可能会被代码中大量使用的Retain和Release方法搞晕。不光大家有这样的感觉&#xff0c;我也有同样的feeling&#xff1a;**Go是GC语言[2]&#x…

MWCS 2023,到底有些啥?(下篇)

█ 亚信科技 5G行业专网一体机&#xff1a; 反光太厉害了&#xff0c;看不太清&#xff1a; 这几张都是小枣妹拍的&#xff0c;^_^&#xff1a; █ 浩鲸科技 浩鲸&#xff0c;就是以前的中兴软创&#xff1a; █ 紫光展锐 6G这块&#xff0c;干货很多&#xff1a; 这次重点展示…

docker容器日志占满硬盘空间的解决方案

目录 原因分析解决方案方案一 定时清空日志文件方案二 全局容器日志大小方案三 修改日志驱动 docker常用清理空间命令 原因分析 由于默认情况下&#xff0c;docker使用json-file类型的日志驱动&#xff0c;该日志驱动默认情况下&#xff0c;每个容器的日志会一直追加在文件名为…

chatgpt赋能python:用Python模拟用户登录,实现多个网站的SEO优化

用Python模拟用户登录&#xff0c;实现多个网站的SEO优化 介绍 在互联网时代&#xff0c;SEO已成为许多网站提高曝光率和流量的重要手段之一。而SEO优化的一个重要方面就是网站的用户登录。然而&#xff0c;手动登录多个网站进行SEO操作是非常耗时耗力的。那么&#xff0c;有…

卷积神经网络实现猫狗分类

目录 一、环境配置二、神经网络CNN1、简介2、CNN结构3、层次说明 三、数据集准备1、下载数据集2、数据集分类 四、 猫狗分类的实例——基准模型1、构建网络模型2、配置训练方法3、转换格式4、模型训练并保存生成的模型5、结果可视化 五、调整基准模型1、图像增强2、增强后的图像…

【C语言初阶(8)】函数1

文章目录 1. 函数的介绍2. 函数的分类2.1 库函数2.2 自定义函数 3. 函数的参数4. 函数的调用4.1 传值调用4.2 传址调用 1. 函数的介绍 1. 什么是函数&#xff1f; 函数是完成特定任务的独立程序代码单元。语法规则定义了函数的结构和使用方式。 一些函数执行某些动作&#xff…

Guava 之 EventBus

​​EvenBus​​​ 是 Guava 中 Pub/Sub 模式的轻量级实现。平时开发如果我们要实现自己的 Pub/Sub 模型&#xff0c;要写不少类&#xff0c;设计也挺复杂&#xff0c;对业务代码也有一定的侵入&#xff0c;但是在使用了 ​​EventBus​​ 之后就很方便了。 在 Pub/Sub 模式中…