关于Spring和缓存雪崩、穿透、击穿、预热的最常见的十道面试题

news2024/11/15 19:53:55

面试题一:什么是缓存雪崩?如何解决缓存雪崩?

缓存雪崩指的是在短时间内,有大量的请求直接查询术后句酷,从而对数据库造成大量的压力,严重情况下可能导致数据库宕机的情况叫做缓存雪崩

我们可以看一下正常的情况下程序执行流程图:

 当出现缓存雪崩的时候,流程图如下:

由此可以看出缓存雪崩造成的影响,导致缓存雪崩的主要原因有以下几种:

  1. 缓存过期时间设置不合理:当大量缓存数据在同一时间失效时,会导致大量请求直接打到数据库或者后端服务
  2. 缓存服务器故障:如果缓存服务器发生故障,无法体哦共缓存服务,那么所有请求都会直接访问数据库或后端服务
  3. 缓存数据的热点分布不均:如果某些热门数据集中一部分缓存节点上,当这些节点发生故障或者数据失效的 ,会导致请求直接打到数据库或者后端服务

如何解决缓存雪崩

缓存雪崩的常见解决方法有以下几种:

  • 随机生成缓存过期时间:随机生成缓存过期时间,可以避免缓存同时过期,从而让避免缓存雪崩问题
//缓存原本的失效时间
int exTime = 10*60;
//随机数生成类
Random random = new Random();
//缓存设置
jedis.setex(cacheKey,exTime+random.nextInt(1000) ,value);
  • 使用多级缓存:可以使用多级缓存架构,将热门数据同时缓存在多个缓存节点上,避免单一节点故障导致请求直接访问数据库或者后端服务,例如可以设计二级换内存(分布式缓存+本地缓存),如图:

  • 缓存过期前预加载:在缓存即将过期之前,提前异步加载缓存,避免在缓存失效时大量请求直接打到数据库或者后端服务
  • 开启限流或降级功能:当缓存发生雪崩时,采用限流或降级的机制来减轻服务器压力,保证系统可用性
  • 实时及监控和预警:通过监控缓存的状态和命中率,及时发现缓存的问题

面试题二:什么是缓存穿透?如何解决缓存穿透?

缓存穿透是指,当我们查询一个数据库和缓存中都不存在的数据时,由于数据库查询结果为空,出于容错考虑,我们通常不会将这个空结果保存到缓存中。因此,每次对这个数据的请求都会直接查询数据库,而不是缓存。这就导致数据库需要处理额外的查询压力,从而可能降低系统的整体性能

简单来说,缓存穿透就是指数据库查询没有数据,出于容错考虑,不会将结果保存到缓存中,因此每次请求都会去查询数据库

缓存穿透执行流程如下:

其中红色路径代表缓存穿透的执行路径,可以看出缓存穿透会给数据库造成很大压力

如何解决缓存穿透

  1. 缓存空对象:对于查询结果为null或不存在的数据,也可以将它们以特殊值(如:NULL或特殊符号)进行缓存,并设置较短的过期时间。这样,短时间相同的查询请求就可以直接从缓存中获得响应,避免了对数据库的直接查询
  2. 布隆过滤器:在请求达到缓存之前,先通过布隆过滤器判断数据可能存在还是一定不存在。对于不存在的数据,可以直接返回;可能存在的则继续查询缓存和数据库。布隆过滤器是一种空间效率极高的概率型数据结构,他会给出“可能存在”或者“一定不存在”的答案
  3. 开启限流功能:当发现大量连续未命中的请求的时候,可以采用限流策略限制同一时间内向数据库发送的查询请求数量,减轻数据库压力

面试题三:什么是缓存击穿?如何解决缓存击穿?

缓存击穿是指某个热点缓存,在某一时刻恰好失效了,然后此时刚好有大量的并发请求,此时这些请求会给数据库造成巨大的压力

缓存击穿的执行流程:

缓存击穿主要的原因是热点数据在缓存中失效或被淘汰,并发请求同属访问该数据,导致缓存无法命中

如何解决缓存击穿 

  • 设置永不过期:对于某些热点缓存,我们可以设置成永不过期,这样就保证缓存的稳定性,但是需要注意在数据更改之后,要及时更新此热点缓存,不然会造成查询结果的误差
  • 缓存过期前预加载:在缓存即将过期之前,提前异步加载缓存,避免在缓存失效时大量的请求直接打到数据库或者后端服务
  • 使用多级缓存:可以使用多级缓存架构,将热门数据同时缓存在多个缓存节点上,避免单一节点故障导致请求直接访问数据库或者后端服务。例如可以设计多级缓存,也就是使用分布式缓存(Redis)+本地缓存(Caffeine/Guava Cache) ,如下图所示:

  • 开启限流或降级功能:当缓存发生雪崩时,采用限流或降级的机制来减轻服务器压力,保证系统可用性

面试题四:什么是缓存预热?如何实现缓存预热?

缓存与炽热是指在系统启动、高峰期来临之前或者数据变更之后,提前将热门或者需要经常访问的数据加载到缓存中,以提高系统的响应性能和缓存命中率。通过缓存预热,可以避免在实际请求到来的时候出现缓存穿透和缓存击穿的情况,减少对后端存储的直接访问

实现缓存你预热的一般步骤如下:

  1. 确定热门数据:首先需要确定哪些数据是热门或者经常访问的数据。可以通过系统日志、业务需求、数据统计分析等方式进行评估
  2. 加载数据到缓存:在系统启动、高峰期来临之前或者数据变更之后,提前将热门数据加载到缓存中。可以通过定时任务、异步加载、批量加载等方式来实现数据加载
  3. 设置适当的过期时间:根据业务需求和数据的访问频率,设置适当的缓存过期时间。过期时间可以根据不同的数据进行灵活调整,以保证缓存数据的有效性
  4. 监控和维护:在缓存预热完成后,需要进行监控和维护。可以通过监控缓存命中率、缓存失效率指标来评估

缓存预热的实现

手动初始化:在程序启动阶段或者服务初始化的时候,通过编写代码主动的从数据库加载热点数据,并将其放入缓存中(如:Redis)

//初始化阶段加载热点数据
public void warmUpCache() {
    List<HotData> hotDatas = loadHotDataFromDatabase();
    for (HotData data : hotDatas) {
        string key = buildKey(data.getId());
        redisTemplate.opsForValue().set(key, data expirationTime TimeUnit.MINUTES);
    }
}

定时任务:使用定时任务定期刷新或者加载数据到缓存中,可以是固定时间间隔,也可以是在数变更后触发

事件驱动:当有新的数据添加到数据库时,触发一个时间来通知缓存系统加载数据

使用框架:某些框架或者中间件提供了缓存预热功能的支持。例如,在Spring Boot项目中,可以通过实现CommandLineRunner或ApplicationRunner接口,在应用启动自动加载数据到缓存

你的代码片段似乎有一些语法错误,我已经为你修正了。在Spring Boot中,一个类可以同时实现CommandLineRunnerApplicationRunner接口,并且可以在run方法中添加自定义的操作。以下是修正后的代码:

import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Component
public class MyRunner implements CommandLineRunner, ApplicationRunner {
    @Override
    public void run(String... args) throws Exception {
        System.out.println("This is CommandLineRunner"); // 实现自定义操作
    }

    @Override
    public void run(ApplicationArguments args) throws Exception {
        System.out.println("This is ApplicationRunner"); // 实现自定义操作
    }
}

在这段代码中,MyRunner类实现了CommandLineRunnerApplicationRunner接口。当Spring Boot应用启动完成后,它会自动执行这两个接口的run方法。在这两个方法中,你可以添加自定义的操作,比如加载数据到缓存(即缓存预热)等

面试题五:在SpringBoot中如何实现缓存预热?

缓存预热是指在项目启动时,预先将数据加载到缓存系统(如Redis)中的一种机制。在Spring Boot项目中,可以通过以下几种方式实现缓存预热123: 

  1. 使用启动监听事件实现缓存预热:可以使用ApplicationListener监听ContextRefreshedEvent或ApplicationReadyEvent等应用上下文初始化完成事件,在这些事件触发后执行数据加载到缓存的操作。 

    @Component 
    
    public class CacheWarmer implements ApplicationListener<ContextRefreshedEvent> { 
    
        @Override 
    
        public void onApplicationEvent(ContextRefreshedEvent event) { 
    
            // 执行缓存预热业务... 
    
            cacheManager.put("key", dataList); 
    
        } 
    
    } 

  2. 使用@PostConstruct注解实现缓存预热:在需要进行缓存预热的类上添加@Component注解,并在其方法中添加@PostConstruct注解和缓存预热的业务逻辑。 

    @Component 
    
    public class CachePreloader { 
    
        @Autowired 
    
        private YourCacheManager cacheManager; 
    
    
    
        @PostConstruct 
    
        public void preloadCache() { 
    
            // 执行缓存预热业务... 
    
            cacheManager.put("key", dataList); 
    
        } 
    
    } 

  3. 使用CommandLineRunner或ApplicationRunner实现缓存预热:CommandLineRunner和ApplicationRunner都是Spring Boot应用程序启动后要执行的接口,它们都允许我们在应用启动后执行一些自定义的初始化逻辑,例如缓存预热。 

    @Component 
    
    public class MyCommandLineRunner implements CommandLineRunner { 
    
        @Override 
    
        public void run(String ... args) throws Exception { 
    
            // 执行缓存预热业务... 
    
            cacheManager.put("key", dataList); 
    
        } 
    
    } 

面试题六:什么是IoC?它解决了什么问题?为什么要使用它?

IoC和AOP是Spring中最核心的两个概念。IoC全称为Inversion of Control,中文意为“控制反转”。它不是一种技术,而是一种设计思想。在Java开发中,IoC意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制它

IoC解决了什么问题

其实IoC就是把具体实例化对象的步骤交给容器处理。这样可以降低对象之间的耦合度,是得资源变得更容易管理

为什么要用IoC

因为IoC可以帮助我们解决传统开发模式中遇到的问题,比如创建了许多重复的对象,造成大量的资源浪费,更换实现类需要改动多个地方,创建和配置组件工作繁杂,给组件调用方带来极大不便。通过使用IoC,我们可以将对象的控制权(创建、管理)交由IoC容器去管理,我们在使用的时候直接向IoC容器“要”就可以了。这样,我们就可以专注于业务逻辑的实现,而不需要关心对象的创建和管理等一系列的事情

面试题七:IoC和DI有什么关系?IoC的实现除了DI之外,还有其他实现方式吗?

IoC(Inversion of Control,控制反转)和DI(Dependency Injection,依赖注入)是两个密切相关的概念,它们都是面向对象编程和设计模式中的重要思想

IoC是一种设计思想,它基本思想是将对象的创建、销毁、依赖关系的维护等控制权从程序代码中转移出去,交给容器管理。这样可以降低对象之间的耦合度,使得资源变得容易管理,利于功能复用,更重要的是使得程序的整个体系结构变得非常灵活

DI是IoC的一种具体的实现方式,它是指将对象锁以来的其他对象(即依赖)通过构造方法、Setter方法或其他方式注入到对象中,从而消除对象之间的耦合关系.DI可以使对象之间的依赖关系更加清晰、简单和可维护

以下是如何在Spring中实现DI:

  1. 构造方法注入:
    @Component
    public class UserService {
        private final DbDriver dbDriver;
    
        public UserService(DbDriver dbDriver) {
            this.dbDriver = dbDriver;
        }
    
        public void doSomethingWithUser() {
            List<User> users = dbDriver.searchUsers();
            // 处理users
        }
    }
    
  2. Setter方法注入:
    @Component
    public class UserService {
        private DbDriver dbDriver;
    
        @Autowired
        public void setDbDriver(DbDriver dbDriver) {
            this.dbDriver = dbDriver;
        }
    
        public void doSomethingWithUser() {
            List<User> users = dbDriver.searchUsers();
            // 处理users
        }
    }
    

总的来说,IoC是一种思想,它强调将对象之间的依赖关系的控制权交给容器来管理;DI则是一种具体的实现方式,它强调将对象所依赖的其他对象通过注入的方式来消除对象之间的耦合关系

面试题八:BeanFactory和FactoryBean有什么区别?

BeanFactory和FactoryBean完全不同的两个接口,BeanFactory是用来管理Bean对象的,而FactoryBean本质上是一个Bean,也是归BeanFactory管理的,但是使用FactoryBean可以来创建普通的Bean对象和AOP代理对象,它们具体区别如下:

BeanFactory:

  • BeanFactory 是 Spring 框架的核心接口之一,用于管理和查找 Spring Bean。
  • 它是一个工厂模式的实现,负责创建和管理 Bean 对象。在 Spring 容器中,BeanFactory 负责实例化、装配和管理 Bean 的生命周期。
  • BeanFactory 的实现类包括 XmlBeanFactoryDefaultListableBeanFactory

其中ApplicationContext就是BeanFactory的子类,咱们通常会使用ApplicationContext来获取某个Bean:

 BeanFactory使用示例:

// 创建BeanFactory容器
BeanFactory beanFactory = new XmlBeanFactory(newClassPathResource("applicationContext.xml"));
// 获取bean实例
YourBean yourBean =(YourBean) beanFactory.getBean("yourBeanName");

BeanFactory的主要使用场景:从IoC容器中获取Bean对象

FactoryBean:

  • FactoryBean 是一个接口,用于创建复杂的 Bean 实例,可以作为一种更高级别的工厂,允许在创建 Bean 时进行更多的控制。
  • 实现 FactoryBean 接口的类必须实现 getObject() 方法,该方法定义了创建和返回实际 Bean 实例的逻辑。
  • 当将实现了 FactoryBean 接口的类配置到 Spring 容器中时,实际上容器会管理这个 FactoryBean 实例,而不是它创建的实际 Bean。要获取实际 Bean,需要调用 FactoryBeangetObject() 方法。
import org.springframework.beans.factory.FactoryBean;

public class MyBean implements FactoryBean<Object> {

    private String message;

    // 通过构造方法初始化实例
    public MyBean() {
        this.message = "通过构造方法初始化实例";
    }

    // 方法增强
    @Override
    public Object getObject() throws Exception {
        // 通过 FactoryBean.getObject() 创建实例
        return new MyBean("通过 FactoryBean.getObject() 创建实例");
    }

    @Override
    public Class<?> getObjectType() {
        return MyBean.class;
    }

    public String getMessage() {
        return message;
    }
}

面试题九:什么是AOP?实际工作中AOP的使用场景有哪些?

AOP(面向切片编程)可以说是OOP(面向对象编程)的补充和完善,OOP引入了封装、继承、多态等概念来建立一种公共对象处理的能力,当我们需要处理公共行为的时候,OOP就会显得无能为力,而AOP的出现正好解决了这个问题。比如统一的日志处理模块、授权验证模块等都可以使用AOP很轻松的处理

AOP主要有以下几种:

  1. 集中处理某一类问题,方便维护
  2. 逻辑更加清晰
  3. 降低模块之间的耦合度

AOP常见的使用场景有以下几种:

  1. 用户登录和鉴权
  2. 统一日志记录
  3. 统一方法执行时间统计
  4. 统一返回格式设置
  5. 统一的异常处理
  6. 声明式事务实现

我们用例子更好的理解,AOP的使用场景:

考虑一个面向对象的情景,有一个服务类 UserService 包含一些方法,如 createUserupdateUser 等。如果我们想要在每个方法执行前后记录日志,可能会倾向于在每个方法中添加日志记录的代码。这可能会导致代码重复,而且如果需要修改日志记录的方式,需要在每个方法中进行修改

public class UserService {
    
    public void createUser(User user) {
        // 日志记录 - 方法开始
        log.info("Creating user: " + user.getName());
        
        // 具体的创建用户逻辑
        // ...
        
        // 日志记录 - 方法结束
        log.info("User created successfully: " + user.getName());
    }

    public void updateUser(User user) {
        // 日志记录 - 方法开始
        log.info("Updating user: " + user.getName());
        
        // 具体的更新用户逻辑
        // ...
        
        // 日志记录 - 方法结束
        log.info("User updated successfully: " + user.getName());
    }

    // 其他方法...
}

在这种情况下,OOP 在处理日志记录时可能显得繁琐,因为我们需要在每个方法中添加相似的日志记录代码

现在,让我们使用 AOP 来处理这个横切关注点。我们可以创建一个日志切面,将日志记录的逻辑从服务类中分离出来。这样,我们只需在切面中定义一次日志记录的逻辑,然后通过配置将切面应用到需要的方法中

@Aspect
@Component
public class LoggingAspect {

    @Before("execution(* com.example.UserService.*(..))")
    public void logMethodStart(JoinPoint joinPoint) {
        log.info("Method start: " + joinPoint.getSignature().toShortString());
    }

    @After("execution(* com.example.UserService.*(..))")
    public void logMethodEnd(JoinPoint joinPoint) {
        log.info("Method end: " + joinPoint.getSignature().toShortString());
    }
}

通过 AOP,我们将日志记录逻辑从业务代码中解耦,实现了统一的日志记录,避免了代码的重复和耦合。这是 AOP 在处理横切关注点时的一个实际应用例子。

面试题十:说一下AOP的底层实现原理?

AOP底层原理可以划分成四个阶段:创建代理对象阶段、拦截目标对象阶段、调用代理对象阶段、调用目标对象阶段

第一阶段:创建代理对象阶段

  1. 通过getBean()方法创建Bean实例
  2. 根据AOP的配置匹配目标类的类名,判断是否满足切面规则,规则指的是:
    // 切面规则:匹配所有以 "Service" 结尾的类的所有方法
    execution(* com.example.*Service.*(..))
    
  3. 如果满足规则,调用ProxyFactory创建代理Bean并缓存到IoC容器中
  4. 根据目标对象的是否实现接口选择不同的代理策略,通常是JDK Proxy(基于接口的代理)或Cglib Proxy(基于类的代理)

目标对象:就是我们自己写的业务代码

第二阶段:拦截目标对象阶段

  1. 当用户调用目标对象的方法的时候,被一个名为AopProxy的对象拦截
  2. AopProxy对象封装了所有的调用策略,并且实现了IncationHandler接口
  3. 在IncationHandler的invoke()方法中,出发了MethodInvocation的proceed()方法
  4. proceed()方法按照顺序执行符合所有AOP拦截规则的拦截器链

其中invoke() 方法用于定义切面的逻辑,而 proceed() 方法用于在拦截器链中继续执行下一个拦截器或最终执行目标方法

MethodInvocation:负责执行拦截器链,在proceed()方法中执行;

第三阶段:调用代理对象阶段

  1. AOP拦截器链中的每个元素被称为MethodInterceptor,即切面配置中的Advice通知
  2. MethodInterceptor接口的invoke()方法被织入的代码片段
  3. 这些被织入的代码片段在这个阶段执行,通常是切片配置中定义的通知方法

织入代码:就是要在我们自己写的业务代码增加的代码片段;

切面通知:就是封装织入代码片段的回调方法;

负责执行织入的代码片段,在invoke()方法中执行。

第四阶段:调用目标对象阶段

  1. MethodInterceptor接口中的invoke()方法触发对目标对象方法的调用,即反射调用目标对象的方法,例如:
    public class MyInterceptor implements MethodInterceptor {
    
        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
            System.out.println("Before method execution");
    
            // 通过反射调用目标对象的方法
            Object result = invocation.proceed();
    
            System.out.println("After method execution");
    
            return result;
        }
    }
    

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

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

相关文章

k8s架构、工作流程、集群组件详解

目录 k8s概述 特性 作用&#xff08;为什么使用&#xff09; k8s架构 k8s工作流程 k8s集群架构与组件 核心组件详解 Master节点 Kube-apiserver Kube-controller-manager Kube-scheduler 存储中心 etcd Node Kubelet Kube-Proxy 网络通信模型 容器引擎 k8s核…

【C语言入门】分支和循环

✨✨欢迎大家来到Celia的博客✨✨ &#x1f389;&#x1f389;创作不易&#xff0c;请点赞关注&#xff0c;多多支持哦&#x1f389;&#x1f389; 所属专栏&#xff1a;C语言 个人主页&#xff1a;Celias blog~ 目录 引言 1. if语句 1.1 if 1.2 else 1.3 if的嵌套 2. 操…

python 正则表达式学习(1)

正则表达式是一个特殊的字符序列&#xff0c;它能帮助你方便的检查一个字符串是否与某种模式匹配。 1. 特殊符号 1.1 符号含义 模式描述^匹配字符串的开头$匹配字符串的末尾.匹配任意字符&#xff0c;除了换行符&#xff0c;当re.DOTALL标记被指定时&#xff0c;则可以匹配包…

计算机设计大赛 协同过滤电影推荐系统

文章目录 1 简介1 设计概要2 课题背景和目的3 协同过滤算法原理3.1 基于用户的协同过滤推荐算法实现原理3.1.1 步骤13.1.2 步骤23.1.3 步骤33.1.4 步骤4 4 系统实现4.1 开发环境4.2 系统功能描述4.3 系统数据流程4.3.1 用户端数据流程4.3.2 管理员端数据流程 4.4 系统功能设计 …

工厂HVAC暖通系统如何实现优化?

在工厂运营中&#xff0c;HVAC暖通系统是维持良好生产环境的关键组成部分。然而&#xff0c;由于能效低下&#xff0c;这些系统可能导致昂贵的能源开支&#xff0c;同时对环境造成负担。本文将深入研究工厂HVAC系统的能效低下原因&#xff0c;介绍HVAC系统优化的关键步骤&#…

老照片模糊不清怎么修复?教你几个修复模糊照片的方法

老照片&#xff0c;如同历史的见证者&#xff0c;承载着家族的记忆与故事。它们无声地诉说着我们的成长轨迹&#xff0c;将那些温馨而美好的瞬间永恒定格。然而&#xff0c;岁月无情&#xff0c;这些老照片逐渐变得模糊不清&#xff0c;甚至布满了岁月的痕迹&#xff0c;令我们…

【第六课课后作业】大模型评测

大模型评测 大模型评测安装环境安装数据准备查看支持的数据集和模型 启动测评评测结果 大模型评测 安装 环境安装 conda create --name opencompass --clone/root/share/conda_envs/internlm-base source activate opencompass git clone https://github.com/open-compass/ope…

防火墙安全策略以及NAT简易拓扑

实验需求 拓扑如下 前期的配置如二层交换机和防火墙的配置就不再赘述 感兴趣的童鞋可以看上一篇博客 防火墙路由模式简易拓扑-CSDN博客 这里主要讲一讲安全策略&#xff0c;用户认证以及NAT策略的配置 配置实现 安全策略 1.生产区在工作时间内可以访问DMZ区&#xff0c;仅…

Python requests网络库源码分析(第三篇:通过学习异常模块,了解http协议)

前言 作者在requests包下&#xff0c;定义了exceptions模块&#xff0c;该模块中定义执行http请求过程中常见的错误&#xff0c;熟悉这些错误有助于我们写出健壮的业务程序&#xff0c;同时还能温习http的知识点&#xff0c;本文基于的requests版本为2.27.1 exceptions模块&…

qt学习:tcp区分保存多个客户端

在前面文掌的tcp客服端服务端进行更改 qt学习&#xff1a;Network网络类tcp客户端tcp服务端-CSDN博客https://blog.csdn.net/weixin_59669309/article/details/135842933?spm1001.2014.3001.5501前面的服务端每次有新的客户端连接&#xff0c;就会覆盖掉原来的指针&#xff0…

Termux结合内网穿透实现无公网ip远程SFTP传输文件

目录 前言 1. 安装openSSH 2. 安装cpolar 3. 远程SFTP连接配置 4. 远程SFTP访问 4. 配置固定远程连接地址 结语 作者简介&#xff1a; 懒大王敲代码&#xff0c;计算机专业应届生 今天给大家聊聊Termux结合内网穿透实现无公网ip远程SFTP传输文件&#xff0c;希望大家能…

CentOS7自动备份数据库到git

虽然数据库没什么数据&#xff0c;但是有就是珍贵的啦&#xff0c;为了服务器什么的无了&#xff0c;所以还是要自动备份一下比较好。 Open备忘第一页 步骤 在Gitee&#xff08;github&#xff09;上创建一个私有仓库Gitee&#xff08;github&#xff09;配置好服务器的ssh在服…

DAY10_SpringBoot—SpringMVC重定向和转发RestFul风格JSON格式SSM框架整合

目录 1 SpringMVC1.1 重定向和转发1.1.1 转发1.1.2 重定向1.1.3 转发练习1.1.4 重定向练习1.1.5 重定向/转发特点1.1.6 重定向/转发意义 1.2 RestFul风格1.2.1 RestFul入门案例1.2.2 简化业务调用 1.3 JSON1.3.1 JSON介绍1.3.2 JSON格式1.3.2.1 Object格式1.3.2.2 Array格式1.3…

mysql 多版本并发控制mvcc

行级锁的一个变种避免了加锁&#xff0c;开销低非阻塞读操作&#xff0c;写操作是行级原理&#xff1a;使用数据在某个时间点的快照实现&#xff0c;不同事务在同一个时间可以看到同一个表中的不同数据。分类&#xff1a;乐观&#xff0c;悲观在一行中存储更多数据&#xff0c;…

芯片查询工具:道合顺电子网助您轻松实现芯片查询、分析与调试

在电子领域&#xff0c;对芯片进行准确的查询、分析和调试是确保设备正常运行和故障排查的关键步骤。为了帮助用户轻松实现这一过程&#xff0c;道合顺电子网提供了一系列高效的芯片查询工具&#xff0c;助您快速获取所需信息、分析数据以及进行灵活的调试操作。 为什么选择道…

SpringMVC-HttpMessageConverter 报文信息转化器

文章目录 HttpMessageConverter一、概念二、RequestBody三、RequestEntity四、 ResponseBody1.返回JSON格式的字符串 五、RestController六、ResponseEntity HttpMessageConverter 一、概念 报文信息转化器&#xff0c;将请求报文转化为Java对象&#xff0c;或将Java对象转化…

使用云手机运营TikTok,实现更多可能性

在数字化时代&#xff0c;社交媒体平台的崛起改变了商业推广和品牌建设的方式。TikTok&#xff0c;作为一款风靡全球的短视频应用&#xff0c;吸引了数以亿计的用户。对于跨境电商和品牌推广而言&#xff0c;使用云手机运营TikTok可以实现多种功能&#xff0c;让运营变得更加灵…

idea中使用带provide修饰的依赖,导致ClassNotFound

1、provide修饰的依赖作用&#xff1a; 编译时起作用&#xff0c;而运行及打包时不起作用。程序打包到Linux上运行时&#xff0c;若Linux上也有这些依赖&#xff0c;为了在Linux上运行时避免依赖冲突&#xff0c;可以使用provide修饰&#xff0c;使依赖不打包进入jar中 2、可能…

再获权威认可!亚信安全实力占据CCSIP 2023全景图75个领域

近日&#xff0c;FreeBuf咨询正式发布《CCSIP&#xff08;China Cyber Security Industry Panorama&#xff09;2023中国网络安全行业全景册&#xff08;第六版&#xff09;》。本次全景册面向广大国内安全厂商&#xff0c;由厂商自主申报并填写信息征集表&#xff0c;经FreeBu…

js中的内置对象、数学对象、日期对象、数组对象、字符串对象

js中的对象&#xff08;三种&#xff09;&#xff1a; 自定义对象 car、computer DOM对象 div、p BOM对象 window、console 内置对象 数学对象 Math &#xff08;object类型&#xff09; 1、圆周率 Math.PI 2、向下取整(返回值) Math.floor() 3、向上取整(返回值) M…