秋招八股学习记录
8.27(周二)
mysql索引失效有哪些场景
- 范围查询:使用 BETWEEN、<、> 等范围操作符时,索引可能只在范围的一部分中使用,或完全失效。
- 函数和运算符:在索引列上使用函数(如 LENGTH(column_name))或运算符(如 column_name + 1)可能导致索引失效。
- 数据类型不匹配:查询条件的数据类型与列的数据类型不匹配(如在 VARCHAR 列上进行数值比较)可能导致索引失效。
- LIKE 查询:以通配符开头(如 LIKE ‘%value%’)的 LIKE 查询通常无法使用索引。
5.NULL 值:在索引列上进行 IS NULL 或 IS NOT NULL 的查询可能不使用索引,具体取决于查询和索引类型。 - 隐式转换:MySQL 可能会进行隐式数据类型转换,导致索引无法被使用。
通过 EXPLAIN 可以帮助了解具体的索引使用情况。
EXPLAIN SELECT * FROM your_table WHERE column_name = 'value';
EXPLAIN 将展示查询的执行计划,包括是否使用了索引以及使用了哪个索引。查看 key 列可以判断具体使用了哪个索引
Redis为什么这么快?
Redis 快速主要因为以下几个原因:
- 内存存储:Redis 将数据完全存储在内存中,避免了磁盘 I/O 的延迟。
- 单线程模型:Redis 使用单线程处理请求,减少了上下文切换和线程同步的开销。
- 高效的数据结构:Redis 使用高效的数据结构(如字符串、哈希、列表、集合等)和优化的算法,减少了操作复杂度。
- 操作原子性:Redis 的操作通常是原子性的,减少了锁和冲突的开销。
- 网络协议优化:Redis 使用简洁的协议(RESP),减少了数据传输的开销。
AOP的应用场景
面向切面编程(Aspect-Oriented Programming, AOP)是一种编程范式,它通过将横切关注点(cross-cutting concerns)从核心业务逻辑中分离出来,帮助提高代码的模块化和可维护性。AOP 的应用场景包括但不限于以下几个方面:
- 日志记录
描述:在应用程序中,记录日志通常是跨越多个模块的功能。使用 AOP,可以在方法调用之前、之后或异常发生时自动插入日志记录代码。
示例:记录方法执行时间、调用参数、返回值或异常信息。 - 性能监控
描述:性能监控涉及测量代码执行时间、资源使用情况等。通过 AOP,可以在方法执行前后插入性能监控代码,而不需要修改核心业务逻辑。
示例:统计某个方法的执行时间或监控方法的调用频率 - 事务管理
描述:事务管理是一个常见的横切关注点,它涉及到数据库操作的开始、提交和回滚。使用 AOP 可以自动管理事务的边界。
示例:在方法执行前开始事务,在方法执行后提交事务或回滚事务。 - 安全控制
-描述:安全控制包括权限检查和访问控制。通过 AOP,可以在方法调用之前插入安全检查逻辑。
示例:检查用户是否有权执行某个操作,或者根据用户角色进行权限控制。 - 缓存
描述:缓存逻辑通常在多个方法中重复出现。使用 AOP,可以在方法调用前检查缓存,并在方法执行后更新缓存。
示例:在方法执行前检查缓存是否存在结果,在方法执行后将结果存入缓存。 - 异常处理
描述:异常处理代码通常与业务逻辑分离。通过 AOP,可以统一处理方法中发生的异常,并记录或处理这些异常。
示例:捕获方法中的异常,并执行相应的异常处理逻辑,如发送报警邮件或记录错误日志。 - 事务处理
描述:事务涉及到业务操作的原子性、隔离性、持久性和一致性。AOP 可以确保在方法执行时自动处理事务的开启、提交和回滚。
-示例:在方法执行前开始事务,在方法执行成功后提交事务,若发生异常则回滚事务。 - 审计
描述:审计跟踪用户行为和系统操作。通过 AOP,可以在方法调用时自动记录操作的审计日志。
示例:记录用户对系统的操作,如数据的创建、更新和删除操作。 - 国际化
描述:国际化涉及到动态地根据用户的区域设置显示不同的语言或格式。通过 AOP,可以在方法执行时动态地处理国际化的相关逻辑。
示例:在方法调用前根据用户的语言设置获取对应的消息或格式。 - 代码注入
描述:在一些场景中,可能需要在运行时动态地注入代码或行为。AOP 可以用于在不修改原有代码的情况下添加新功能。
示例:向方法中注入额外的逻辑,如监控、统计或修复。
注:苍穹外卖项目实现的公共字段填充用到了AOP
AOP 通过引入切面(Aspect)、连接点(Join Point)、通知(Advice)和切点(Pointcut)等概念,能够将这些横切关注点从核心业务逻辑中分离出来,从而使得代码更加模块化和易于维护。
Spring 单例和多例的区别?
- 单例(Singleton):一个Spring容器中只有一个实例。适用于共享状态和跨多个请求的场景。需要注意线程安全。
- 多例(Prototype):每次请求都会创建一个新实例。适用于需要隔离状态的场景,不需要线程安全考虑。
使用for循环遍历ArrayList, 在其过程中删除和添加元素有什么影响?那么想要遍历的过程中添加或删除ArrayList元素,怎么做?
- ConcurrentModificationException:如果在使用增强型 for 循环(即 for-each 循环)或普通的 for 循环遍历 ArrayList 时直接调用 remove 方法,会引发 ConcurrentModificationException。这是因为 ArrayList 在遍历时会保持一个内部的修改计数器(modCount),直接修改集合会使这个计数器与期望的值不一致,从而抛出异常。
- 如果你使用的是增强型 for 循环(for-each 循环)(普通for循环也不能添加),在遍历过程中添加元素同样会导致 ConcurrentModificationException。这种异常是因为添加元素修改了集合的结构,而增强型 for 循环内部并不支持这种修改。
- 删除元素:使用 Iterator 的 remove 方法来安全地删除元素,避免 ConcurrentModificationException
- 增加元素:遍历后再添加或者在遍历时使用临时集合记录要添加或删除的元素,并在遍历结束后再进行批量处理
镜像和容器的区别
镜像和容器是 Docker 的两个核心概念。镜像是一个只读的模板,包含了运行应用所需的所有代码、库和依赖。容器则是镜像的一个可运行实例,它是镜像的一个可变副本,用于实际执行应用程序。镜像可以被多个容器共享,而容器在运行时可以进行状态修改,隔离地执行应用。
Java会出现内存泄漏吗?什么时候
是的,Java 中确实可能出现内存泄漏。常见的场景包括:
- 持有不再使用的对象引用:如果对象被保存在静态字段或集合中,且未能及时释放,可能导致内存泄漏。
- 监听器和回调未被取消:注册的监听器或回调如果没有被正确移除,可能会导致内存泄漏。
- 线程池中的任务:如果线程池的任务没有正确处理,可能导致线程及其相关对象被长时间持有。
- 类加载器泄漏:在动态加载和卸载类的过程中,类加载器持有的类可能导致内存泄漏,特别是在 Web 应用中。
Springboot如何注入一个bean?
- 使用@Bean注解
- 使用@Component注解
@Bean和@Component有什么区别?@Service和@Component有什么区别
@Bean:
用于方法上,定义 Bean 的创建逻辑。
主要用于配置类中,适用于需要创建和配置 Bean 的场景。
@Component:
用于类上,标记该类为 Spring 管理的 Bean。
适用于自动扫描和自动装配的场景。
@Service:
@Service 是 @Component 的一个派生注解,用于标记服务层的 Bean。
通常用于业务逻辑层的 Bean。
提供语义上的清晰度,表明该 Bean 主要用于业务逻辑处理。
@Component:
@Component 是一个通用的构造注解,适用于任何 Spring 管理的组件。
可以用于数据访问层、业务逻辑层或其他组件。
springboot有哪些格式的配置文件?yml和properties哪个优先级高?可以同时存在吗?
application.properties:标准的属性文件格式。
application.yml 或 application.yaml:YAML 格式的配置文件,支持层级结构。
优先级:application.yml 和 application.properties 文件的优先级相同,Spring Boot 会根据文件位置、环境等进行合并。具体来说,如果两个文件中有相同的配置项,application.yml 和 application.properties 会合并,通常 application.properties 文件中的配置会覆盖 application.yml 文件中的配置。
同时存在:可以同时存在两个文件。Spring Boot 会加载两个文件的配置,并将其合并
什么是redis的缓存雪崩?怎么解决?
缓存雪崩指的是大量缓存失效或过期,导致大量请求直接打到数据库上,从而引发数据库负载剧增甚至崩溃。
解决方法
- 设置缓存过期时间:使用不同的过期时间,避免缓存同时过期。
- 使用缓存预热:在系统启动或更新时,预加载热点数据到缓存。
- 缓存更新策略:采用定时任务或异步更新缓存的方式,而不是依赖缓存的过期。
- 熔断机制:当缓存击穿时,使用降级策略来处理请求,减少对数据库的压力。
- 使用多级缓存:在缓存失效时,首先从一级缓存中获取数据,如果一级缓存失效再请求二级缓存。
微信小程序登录流程
微信授权登录小程序的流程原理的细节如下:
- 小程序端,调用wx.login()获取code,就是授权码。
- 小程序端,调用wx.request()发送请求并携带code,请求开发者服务器(自己编写的后端服务)。
- 开发者服务端,通过HttpClient向微信接口服务发送请求,并携带appId+appsecret+code三个参数。
- 开发者服务端,接收微信接口服务返回的数据,session_key+opendId等。opendId是微信用户的唯一标识。
- 开发者服务端,自定义登录态,生成令牌(token)和openid等数据返回给小程序端,方便后绪请求身份校验。
- 小程序端,收到自定义登录态,存储storage。
- 小程序端,后绪通过wx.request()发起业务请求时,携带token。
- 开发者服务端,收到请求后,通过携带的token,解析当前登录用户的id。
- 开发者服务端,身份校验通过后,继续相关的业务逻辑处理,最终返回业务数据。