【面试深度解析】腾讯音乐校招 Java 后端一面:SpringBoot工作机制、缓存雪崩、数据一致性、MySQL索引失效(下)

欢迎关注公众号(通过文章导读关注:【11来了】),及时收到 AI 前沿项目工具及新技术的推送!

在我后台回复 「资料」 可领取编程高频电子书
在我后台回复「面试」可领取硬核面试笔记

文章导读地址:点击查看文章导读!

感谢你的关注!

腾讯音乐校招 Java 后端一面:SpringBoot工作机制、缓存雪崩、数据一致性、MySQL索引失效(下)

题目分析

8、SpringBoot 的工作机制?

这里问的应该就是 SpringBoot 自动装配的原理了

SpringBoot 项目特殊的地方就在于入口,通过 @SpringBootApplication 注解标注了 main() 方法用于启动项目,那么自动装配就是通过这个注解来实现的,通过自动装配来将一些默认的 Bean 以及第三方 jar 包所提供的一些 Bean 给加载到 Spring 的容器中:

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

接下来,我们看一看这个 @SpringBootApplication 注解到底包含了什么东西:

// ... 省略非核心注解
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(/*太长,省略部分内容*/)
public @interface SpringBootApplication {
}

其实就是包含了一些子注解,其中有 3 个注解是是比较核心的:@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan

接下来分别说一下这 3 个注解是做什么的

  • @ComponentScan

先从最简单的注解说起,这个注解应该都比较熟悉,用于扫描当前类所在的包下的类到 Spring 的容器中去,将类都扫描成 Spring 的 Bean

  • @SpringBootConfiguration
// ... 省略非核心注解
@Configuration
public @interface SpringBootConfiguration {
}

这个注解其实就是 @Configuration 包装而成的,表明自己是一个配置类

比如我们平时需要向 Spring 中注入一些 Bean 的话,就定义一个配置类再加上 @Configuration 注解,告诉 Spring 我写的这个类是配置类,需要进行扫描

  • @EnableAutoConfiguration
// ... 省略非核心注解
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {
}

这个注解的作用就是开启自动配置的功能,也就是帮助我们自动载入程序运行所需要的默认配置,这个注解是由连两个注解组成:@AutoConfigurationPackage、@Import

**@AutoConfigurationPackage:**这个注解内部也是 @Import 注解,通过 @Import 注解导入一个类,Spring 在扫描的时候,会去扫描到 @Import 导入的类,并且执行这个类中的指定方法

那么 @AutoConfigurationPackage 注解中 @Import 的这个类的作用,就是去将 SpringBoot 主启动类所在的包及其子包下的类扫描到 Spring 的容器中去

**@Import:**接下来说一下 @Import 注解导入的类 AutoConfigurationImportSelector 的作用,他的作用就是扫描所有 jar 包下的 META-INF/spring.factories 文件,spring.factories 中的数据是以 key-value 的形式存放的,里边写了需要加载的自动配置类的全路径,通过 @Import 注解将 spring.factories 文件加载进来,并且去加载该文件中配置的自动配置类

在写 SpringBoot Starter 的时候,就需要在 spring.factories 文件中写自动配置类,来让 Spring 扫描到我们写的 starter 中的配置类

这里如果不清楚一些细节的东西的话,也不要紧,可以先把整体的流程理清楚,具体细节再慢慢通过学习 Spring 源码深入了解

9、缓存雪崩解决方案?

缓存雪崩造成的原因是:大量缓存数据在同一时间过期或者Redis宕机,此时如果有大量的请求无法在 Redis 中处理,会直接访问数据库,从而导致数据库的压力骤增,甚至数据库宕机

缓存过期解决:

  1. 给过期时间加上一个随机数
  2. 互斥锁,当缓存失效时,加互斥锁,保证同一时间只有一个请求来构建缓存
  3. 缓存预热,在系统启动前,提前将热点数据加载到缓存中,避免大量请求同时访问数据库

Redis故障解决:

  1. 服务熔断或请求限流
  2. 构建 Redis 缓存高可靠集群

10、多级缓存如何保证数据一致性?

这里说一下使用 Redis 缓存 + MySQL 如何保证数据一致性(对于本地缓存 + Redis 缓存也是同理):

那么保证数据一致性就需要保证数据库和缓存同时进行更新,那么就分为两种情况先更新数据库还是先更新缓存,由于更新缓存成本比较高(因为写入数据库的值有时候不是直接写入缓存而是经过一系列计算之后才写入缓存,因此当数据修改时不更新缓存,直接将缓存删除),那么就分为了 先删除缓存再更新数据库先更新数据库,再删除缓存 两种情况:

  • 先删除缓存,再更新数据库 (操作简单)

    这种情况造成的缓存不一致为:线程 A 先删除缓存,再去更新数据库,在线程 A 更新数据库之前,如果线程 B 去读取缓存,发现并不存在,去读取数据库,此时读取的是旧数据,再将旧数据写入缓存,此时缓存存储的就是脏数据了。

    使用更新数据库 + 延时双删可以解决此情况的数据不一致,在延时双删中,会删除两次缓存,分为以下几步:

    1. 删除缓存
    2. 更新数据库
    3. 睡眠  Thread.sleep()
    4. 再删除缓存
    

    即延时双删在线程 A 更新完数据库之后,休眠一段时间,再去删除缓存中可能存在的脏数据。

    使用延时双删的话,因为需要隔一段时间再去删除缓存,可能会导致整个操作耗时过长,因此可以将第二次删除缓存的操作异步化

  • 先更新数据库,再删除缓存

    这种情况可能因为线程 A 没有及时删除缓存或者删除缓存失败而导致线程 B 读取到旧数据

    因此当缓存删除失败时,可以使用消息队列来重试,流程如下:

    1. 先将要删除的缓存值或者是要更新的数据库值暂存到消息队列中
    2. 当程序没有成功删除缓存值或者更新数据库值时,从消息队列中读取这些值,再次进行删除或更新
    3. 如果成功删除缓存或者更新数据库,要将这些值从消息队列中取出,以免重复操作

上边两种保证数据一致性的方法,操作上比较简单,性能也比较好,但是整个缓存删除的操作和业务代码耦合度比较高并且不能保证严格的一致性,如果需要更严格的一致性保障可以选择通过 Canal + MQ 的组合来保证,但相对应的就是会提升系统的复杂性,可以根据具体需求来进行选择

Canal + MQ 方式保证数据一致性::通过 Canal + RocketMQ 实现缓存数据库的一致性

通过 canal + RocketMQ 来实现数据库与缓存的最终一致性,对于数据直接更新 DB 的情况,通过 canal 监控 MySQL 的 binlog 日志,并且发送到 RocketMQ 中,MQ 的消费者对数据进行消费并解析 binlog,过滤掉非增删改的 binlog,那么解析 binlog 数据之后,就可以知道对 MySQL 中的哪张表进行 增删改 操作了,那么接下来我们只需要拿到这张表在 Redis 中存储的 key,再从 Redis 中删除旧的缓存即可,那么怎么取到这张表在 Redis 中存储的 key 呢?

可以我们自己来进行配置,比如说监控 sku_info 表的 binlog,那么在 MQ 的消费端解析 binlog 之后,就知道是对 sku_info 表进行了增删改的操作,那么假如 Redis 中存储了 sku 的详情信息,key 为 sku_info:{skuId},那么我们就可以在一个地方对这个信息进行配置:

// 配置下边这三个信息
tableName = "sku_info"; // 表示对哪个表进行最终一致性
cacheKey = "sku_info:"; // 表示缓存前缀
cacheField = "skuId"; // 缓存前缀后拼接的唯一标识// data 是解析 binlog 日志后拿到的 key-value 值,data.get("skuId") 就是获取这一条数据的 skuId 属性值
// 如下就是最后拿到的 Redis 的 key
redisKey = cacheKey + data.get(cacheField)

那么整体的流程图如下:

请添加图片描述

11、MySQL 索引失效的几种情况?

接下来说一下 MySQL 在哪些情况下索引会失效,在实际使用的时候,要尽量避免索引失效:

  • 使用左模糊查询
select id,name,age,salary from table_name where name like '%lucs';

在进行 SQL 查询时,要尽量避免左模糊查询,因为索引进行排序的话,是从左到右进行排序的,如果左边都模糊的话,就不遵守排序的规则了,自然也无法走索引

可以改为右模糊查询,在右模糊查询的情况下一般都会走索引

select id,name,age,salary from table_name where name like 'lucs%';
  • 不符合最左前缀原则的查询

对于联合索引(a,b,c),来说,不能直接用 b 和 c 作为查询条件而直接跳过 a,这样就不会走索引了

如果查询条件使用 a,c,跳过了 b,那么只会用到 a 的索引

  • 联合索引的第一个字段使用范围查询

比如联合索引为:(name,age,position)

select * from employees where name > 'LiLei' and age = 22 and position ='manager';

如上,联合索引的第一个字段 name 使用范围查询,那么 InnoDB 存储引擎可能认为结果集会比较大,如果走索引的话,再回表查速度太慢,所以干脆不走索引了,直接全表扫描比较快一些

可以将范围查询放在联合索引的最后一个字段

  • 对索引列进行了计算或函数操作

当你在索引列上进行计算或者使用函数,MySQL 无法有效地使用索引进行查询,索引在这种情况下也会失效,如下:

select * from employees where LEFT(name,3) = 'abc';

应该尽量避免在查询条件中对索引字段使用函数或者计算。

  • 使用了 or 条件

当使用 or 条件时,只要 or 前后的任何一个条件列不是索引列,那么索引就会失效

select * from emp where id = 10010 or name = 'abcd';

如上,假如 name 列不是索引列,即使 id 列上有索引,这个查询语句也不会走索引

  • 索引列上有 Null 值
select * from emp where name is null;

如上,name 字段存在 null 值,索引会失效

应该尽量避免索引列的值为 null,可以在创建表的时候设置默认值或者将 null 替换为其他特殊值。

12、算法:接雨水

这个算法题也是比较常见的了

题目的意思是给了 n 个柱子的高度,每个柱子的宽度都为 1,问下雨之后能接到多少的雨水,如下图:

请添加图片描述

其中黑色的表示柱子,蓝色的表示接到的雨水

对于每一个柱子来说,只有两边都存在比他高的柱子,那么在这块柱子上边才可以接到雨水,具体在这块柱子上可以接到多少雨水取决于两边都比他高的柱子的最小高度

如上图,对于第 2 块柱子来说,左边第 1 块柱子比他高,右边的话第 7 块柱子比他高,所以在第2 块柱子上一定是可以接到雨水的,能接到多少雨水就取决于两边柱子较低的那一个,也就是左边的第 1 块柱子高度为 1,所以对于第 2 块柱子来说,可以接到的雨水就是 1

所以对每块柱子都计算出来左边和右边比他高的最高的柱子,再逐个计算就可以了,下边给出代码,在 LeetCode 上可以直接运行

class Solution {public int trap(int[] h) {int n = h.length;int[] l_max = new int[n];int[] r_max = new int[n];int last = 0;for (int i = 0; i < n; i ++) {l_max[i] = Math.max(last, h[i]);last = Math.max(last, h[i]);}last = 0;for (int i = n-1; i >= 0; i --) {r_max[i] = Math.max(last, h[i]);last = Math.max(last, h[i]);}int res = 0;for (int i = 0; i < n; i ++) {int h_min = Math.min(l_max[i], r_max[i]);if (h_min - h[i] > 0) {res += h_min - h[i];}}return res;}
}

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

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

相关文章

运维自动化bingo前端

项目目录结构介绍 项目创建完成之后&#xff0c;我们会看到bingo_web项目其实是一个文件夹&#xff0c;我们进入到文件夹内部就会发现一些目录和文件&#xff0c;我们简单回顾一下里面的部分核心目录与文件。 ├─node_modules/ # node的包目录&#xff0c;项目运行的依赖包…

【漏洞库】O2OA系统

O2OA invoke 后台远程命令执行漏洞 CNVD-2020-18740 漏洞描述 O2OA是一款开源免费的企业及团队办公平台,提供门户管理、流程管理、信息管理、数据管理四大平台,集工作汇报、项目协作、移动OA、文档分享、流程审批、数据协作等众多功能,满足企业各类管理和协作需求。 O2OA系…

LeetCode:2.两数相加

目录 题目&#xff1a;​编辑2. 两数相加 - 力扣&#xff08;LeetCode&#xff09; 分析问题&#xff1a; 官方的优秀代码博主的注释&#xff1a; 博主的辣眼代码&#xff0c;无注释&#xff0c;拉出来拷打自己&#xff1a; 每日表情包&#xff1a; 2. 两数相加 - 力扣&am…

面试经典150题——文本左右对齐(困难)

​"It always seems impossible until it’s done." - Nelson Mandela 1. 题目描述&#xff1a; 这个题目标为困难题目&#xff0c;但是如果我们静下心来把题目读懂了&#xff0c;其实无非就是不同情况下不同考虑而已&#xff0c;也没什么思维上的复杂&#xff0c;还…

Linux openKylin(开放麒麟)系统SSH服务安装配置与公网远程连接

文章目录 前言1. 安装SSH服务2. 本地SSH连接测试3. openKylin安装Cpolar4. 配置 SSH公网地址5. 公网远程SSH连接6. 固定SSH公网地址7. SSH固定地址连接8. 结语 前言 openKylin是中国首个基于Linux 的桌面操作系统开发者平台&#xff0c;通过开放操作系统源代码的方式&#xff…

C++:第十五讲高精度算法

每日C知识 system("color xx);是改变字体及背景颜色&#xff0c;前一个x代表一个数字&#xff0c;可以改变背景颜色&#xff0c;后一个x代表一个数字&#xff0c;可以改变字体颜色 &#xff0c;但都是根据颜色表来的。 记住&#xff1a;要加头文件&#xff1a;#include&l…

手写分布式存储系统v0.3版本

引言 承接 手写分布式存储系统v0.2版本 &#xff0c;今天开始新的迭代开发。主要实现 服务发现功能 一、什么是服务发现 由于咱们的服务是分布式的&#xff0c;那从服务管理的角度来看肯定是要有一个机制来知道具体都有哪些实例可以提供服务。举个例子就是&#xff0c;张三家…

DevOps落地笔记-07|案例分析:如何有效管理第三方组件

上一讲主要介绍了如何通过代码预检查的方式提高入库代码的质量&#xff0c;将代码检查尽可能前置&#xff0c;降低修复问题的成本&#xff0c;从而提高交付软件的质量。除了代码本身的问题&#xff0c;依赖组件也是经常困扰开发者的一个问题。比如&#xff0c;依赖组件的某个版…

认识Tomcat (一)

认识Tomcat &#xff08;一&#xff09; 一、服务器 1.1 服务器简介 ​ 硬件服务器的构成与一般的PC比较相似&#xff0c;但是服务器在稳定性、安全性、性能等方面都要求更高&#xff0c;因为CPU、芯片组、内存、磁盘系统、网络等硬件和普通PC有所不同。 ​ 软件服务器&…

深度学习(生成式模型)—— Consistency Models

文章目录 前言预备知识&#xff1a;SDE与ODEMethod实验结果 前言 Diffusion model需要多次推断才能生成最终的图像&#xff0c;这将耗费大量的计算资源。前几篇博客我们已经介绍了加速Diffusion model生成图像速率的DDIM和Stable Diffusion&#xff0c;本节将介绍最近大火的Co…

【Matplotlib】figure方法 你真的会了吗!?

&#x1f388;个人主页&#xff1a;甜美的江 &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;matplotlib &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共同学习、交流进…

解放双手!ChatGPT助力编写JAVA框架!

摘要 本文介绍了使用 ChatGPT逐步创建 一个简单的Java框架&#xff0c;包括构思、交流、深入优化、逐步完善和性能测试等步骤。 亲爱的Javaer们&#xff0c;在平时编码的过程中&#xff0c;你是否曾想过编写一个Java框架去为开发提效&#xff1f;但是要么编写框架时感觉无从下…

Tauri:相比Electron,还有很长路要走的。

一、Tauri是什么 Tauri是一个开源的框架&#xff0c;用于构建跨平台的桌面应用程序。它允许开发者使用Web技术&#xff08;如HTML、CSS和JavaScript&#xff09;来构建高性能的本地应用程序&#xff0c;同时提供了访问底层操作系统功能的能力。 Tauri的设计目标是提供一种简单…

第97讲:MHA高可用集群模拟主库故障以及修复过程

文章目录 1.分析主库故障后哪一个从库会切换为主库2.模拟主库故障观察剩余从库的状态2.1.模拟主库故障2.3.当前主从架构 3.修复故障的主库3.1.修复主库3.2.当前主从架构3.3.恢复MHA 1.分析主库故障后哪一个从库会切换为主库 在模拟MHA高可用集群主库故障之前&#xff0c;我们先…

【JavaSE篇】——抽象类和接口

目录 &#x1f393;抽象类 &#x1f388;抽象类语法 &#x1f388;抽象类特性 &#x1f388;抽象类的作用 &#x1f393;接口 &#x1f388;语法规则 &#x1f388;接口特性 &#x1f388;接口使用(实现USB接口&#xff09; &#x1f388;实现多个接口 &#x1f388;…

力扣刷题之旅:进阶篇(一)

力扣&#xff08;LeetCode&#xff09;是一个在线编程平台&#xff0c;主要用于帮助程序员提升算法和数据结构方面的能力。以下是一些力扣上的入门题目&#xff0c;以及它们的解题代码。 --点击进入刷题地址 题目1&#xff1a;三数之和 题目描述&#xff1a; 给定一个包含n个…

代码随想录算法训练营第41天 | 343.整数拆分 + 96.不同的二叉搜索树

今日任务 343. 整数拆分 96.不同的二叉搜索树 343.整数拆分 - Medium 题目链接&#xff1a;力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 给定一个正整数 n &#xff0c;将其拆分为 k 个 正整数 的和&#xff08; k > 2 &#xff09;&#xff0…

springboot+vue实现excel导出

后端 导入pom依赖 <dependency>x<groupId>cn.afterturn</groupId><artifactId>easypoi-spring-boot-starter</artifactId><version>4.2.0</version> </dependency> Entity实体类 这里以User为例&#xff0c;可按照自己实际…

vulhub中AppWeb认证绕过漏洞(CVE-2018-8715)

AppWeb是Embedthis Software LLC公司负责开发维护的一个基于GPL开源协议的嵌入式Web Server。他使用C/C来编写&#xff0c;能够运行在几乎先进所有流行的操作系统上。当然他最主要的应用场景还是为嵌入式设备提供Web Application容器。 AppWeb可以进行认证配置&#xff0c;其认…

【CSS】css如何实现字体大小小于12px?

【CSS】css如何实现字体大小小于12px? 问题解决方案transform: scale(0.5)&#xff08;常用&#xff09;SVG 矢量图设置text 问题 文字需要显示为12px&#xff0c;但是小于12px的&#xff0c;浏览器是显示不来的 解决方案 transform: scale(0.5)&#xff08;常用&#xff0…