欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 健康 > 美食 > Java 高频面试闯关秘籍

Java 高频面试闯关秘籍

2025/2/13 3:11:32 来源:https://blog.csdn.net/kjl536566/article/details/145580531  浏览:    关键词:Java 高频面试闯关秘籍

目录

  1. Java基础篇:涵盖OOP、多线程、集合等基础知识。
  2. Java高级篇:深入探讨HashMap、JVM、线程池等高级特性。
  3. Java框架篇:介绍Spring、SpringMVC、MyBatis等常用框架。
  4. Mysql数据库篇:包含SQL语句、事务、索引等数据库知识。
  5. 分布式技术篇:讲解Redis、消息队列、ElasticSearch等分布式技术。
  6. 项目管理工具Git篇:阐述Git的使用流程和常见命令。
  7. 综合问题篇:涉及项目经验、并发问题、设计模式等综合问题。
  8. 数据结构和算法篇:介绍数组、链表、排序算法等数据结构与算法。
  9. 设计模式篇:讲解单例模式、工厂模式、代理模式等设计模式。
  10. 面试技巧篇:提供面试过程中的关键要点和技巧。

Java基础篇

1. OOP面向对象

  • 继承:从已有类获取信息创建新类。
  • 封装:将数据和操作数据的方法绑定,控制数据访问。
  • 多态性:不同子类型对象对同一消息作出不同响应。
  • 重载与重写:重载发生在本类,方法名相同;重写发生在父子类之间,方法名和返回值类型相同,重写方法访问权限不能比父类更严格。
  • 抽象类与接口:抽象类需被子类继承,接口需被类实现。接口可多继承,类只能单继承。抽象类有构造器,接口没有。抽象类抽象方法修饰符多样,接口只能是public。抽象类有成员变量,接口只能声明常量。

2. 深拷贝与浅拷贝

  • 浅拷贝:拷贝基本数据类型值和对象引用地址,不复制引用指向的对象。
  • 深拷贝:拷贝基本数据类型值,也复制引用指向的对象。

3. Thread类中的方法

  • sleep(1000):线程睡眠1秒,释放CPU但不释放锁资源。
  • wait(1000):线程等待1秒,释放CPU和锁资源,需配合synchronized使用。
  • wait():一直等待,需通过notify或notifyAll唤醒,同样需配合synchronized使用。

4. int和Integer的区别

  • 数据类型:int是基本数据类型,Integer是包装类。
  • 装箱与拆箱:装箱将基本类型转换为包装类对象,拆箱则相反。自动装箱和拆箱是编译器语法糖,底层通过Integer.valueOf()和Integer.intValue()实现。
  • 使用方式:Integer变量需实例化后使用,int变量不需要。Integer是对象引用,int直接存储数据值。Integer默认值是null,int默认值是0。

5. ==和equals区别

  • ==:比较基本数据类型时比较值,比较引用数据类型时比较地址值。
  • equals:未重写时比较地址值,重写后通常比较对象属性内容。equals方法继承自Object类,默认实现使用==。

6. String类相关

  • 不可继承原因:String类被final修饰,禁止继承和重写,以提高效率和保证安全,其内部有native方法调用操作系统API。
  • StringBuffer和StringBuilder:方法和功能等价,StringBuffer方法多由synchronized修饰,线程安全但效率低;StringBuilder未修饰,线程不安全但效率高。

7. final、finally、finalize

  • final:修饰类、变量和方法。修饰类时不能被继承,修饰变量时为常量,修饰方法时不能在子类中重写。
  • finally:放在try…catch后,程序无论正常执行还是异常,只要JVM不关闭都能执行,用于释放外部资源。
  • finalize:Object类中的方法,垃圾收集器销毁对象时调用,可重写用于清理系统资源。

8. Object类中的方法

  • clone():创建并返回对象副本。
  • equals(Object obj):判断其他对象是否与此对象“相等”。
  • finalize():垃圾回收器确定对象无更多引用时调用。
  • getClass():返回对象的运行时类。
  • hashCode():返回对象的哈希码值。
  • notify():唤醒在此对象监视器上等待的单个线程。
  • notifyAll():唤醒在此对象监视器上等待的所有线程。
  • wait():导致当前线程等待,直到其他线程调用notify()或notifyAll()方法。
  • wait(long timeout):等待指定时间,若超时未被唤醒则继续执行。
  • wait(long timeout, int nanos):更精确控制等待时间。

9. 集合体系

集合框架包含Collection和Map接口。Collection接口下有List和Set子接口,List有序可重复,Set无序不重复。Map接口用于存储键值对。常见实现类有ArrayList、LinkedList、HashSet、TreeSet、HashMap、TreeMap等。

10. HashMap底层结构及原理

  • 结构:JDK1.7中由数组+链表实现,JDK1.8中由数组+链表+红黑树实现。
  • 原理:数组存储数据,链表解决哈希冲突,JDK1.8中链表长度大于阈值(默认为8)且数组长度大于64时,链表转换为红黑树以提升查询性能。
  • 与HashTable区别:HashMap线程不安全,HashTable线程安全;HashMap只有containsValue和containsKey方法,HashTable有contains、containsKey和containsValue三个方法;HashMap允许null作为键和值,HashTable不允许;HashMap默认容量为16,要求底层数组容量为2的整数次幂,扩容时容量变为原来的2倍;HashTable默认容量为11,不要求容量为2的整数次幂,扩容时容量变为原来的2倍加1。

11. 线程的创建方式

  • 继承Thread类:创建Thread类的子类并重写run方法。
  • 实现Runnable接口:实现Runnable接口的run方法,创建Thread对象时传入该实现类实例。
  • 使用Callable和Future:实现Callable接口的call方法,通过FutureTask获取返回值。
  • 使用线程池:通过线程池管理和复用线程,提高效率。

12. 线程的状态转换

线程状态包括新建、就绪、运行、阻塞和死亡。新建状态下线程对象被创建;就绪状态下线程等待CPU调度;运行状态下线程获取CPU执行;阻塞状态下线程因获取锁失败、调用sleep()或join()方法、发出I/O请求等原因暂停运行;死亡状态下线程执行结束或因异常退出run方法。

13. Java中的流

Java流分为字节流和字符流。字节流包括InputStream和OutputStream,用于处理原始字节数据;字符流包括Reader和Writer,用于处理字符数据。还有缓冲流、转换流等,提高流操作的性能和功能。

14. 常见的RuntimeException

  • NullPointerException:调用未经初始化或不存在的对象。
  • ClassNotFoundException:指定的类找不到。
  • NumberFormatException:字符串转换为数字异常。
  • IndexOutOfBoundsException:数组越界异常。
  • ClassCastException:数据类型转换异常。

15. 反射机制

Java反射机制允许在运行时获取类的信息并动态调用对象方法。借助class、Constructor、Field、Method四个类实现,可在运行时判断对象所属类、构造对象、获取类的成员变量和方法等。

16. 序列化

序列化用于解决对象流读写操作问题。实现Serializable接口,使用ObjectOutputStream将对象写出,使用ObjectInputStream恢复对象。

17. Http常见的状态码

  • 200 OK:客户端请求成功。
  • 301 Permanently Moved:请求的URL已永久移走,Response中应包含Location URL。
  • 302 Temporarily Moved:临时重定向。
  • 404 Not Found:服务器无法找到请求的资源。
  • 500 Internal Server Error:服务器发生不可预期的错误。

18. GET和POST的区别

  • 数据传输方式:GET请求数据附在URL后,POST请求数据在请求体中。
  • URL长度限制:GET请求受浏览器和服务器限制,POST请求理论上无长度限制。
  • 安全性:POST安全性高于GET,GET提交数据可能导致用户名和密码明文出现在URL上,存在安全风险。

19. cookie和session的区别

  • 存储位置:cookie存储在客户端浏览器,session存储在服务器端。
  • 工作机制:cookie随请求发送给服务器,session通过会话ID识别用户。
  • 存储数据类型和大小:cookie只能存储字符串类型数据,存储量有限;session可存储任意Java对象。

Java高级篇

1. JVM内存分区及作用

JVM内存分为方法区、虚拟机栈、本地方法栈、堆和程序计数器。

  • 方法区:存储已加载的类信息、常量、静态变量等,很少发生垃圾回收。
  • 虚拟机栈:为Java方法服务,每个方法执行时创建栈帧,存储局部变量表、操作数栈等,线程私有。
  • 本地方法栈:为Native方法服务,与虚拟机栈类似。
  • :所有线程共享,几乎所有对象实例在此创建,频繁发生垃圾回收。
  • 程序计数器:记录当前线程执行的字节码指令地址,是唯一不会出现OOM的区域。

2. Java中垃圾收集的方法

采用分区分代回收思想,年轻代使用复制算法,老年代一般由标记清除或标记清除与标记整理的混合实现。

  • 引用计数法:通过对象引用计数器判断对象是否存活,无法解决循环引用问题。
  • 可达性算法:以GC Roots对象为起点,通过引用链判断对象是否可达,不可达则可被回收。可作为GC Roots的对象有虚拟机栈中引用的对象、方法区类静态属性引用的对象等。

3. StackOverflowError和OutOfMemoryError

  • StackOverflowError常见原因:无限递归循环调用、执行大量方法导致线程栈空间耗尽、方法内声明海量局部变量等。
  • OutOfMemoryError常见原因:内存中数据过多、对象无法被回收等。
  • 排查方法:可通过jvisualvm进行内存快照分析。

4. 线程池

  • 概念:事先将多个线程对象放入容器,使用时直接从池中获取线程,节省线程创建时间,提高效率。
  • 创建方式:通过Executors工具类创建,如newCachedThreadPool、newFixedThreadPool、newScheduledThreadPool、newSingleThreadExecutor等。
  • 底层工作原理:提交任务时,若核心线程池未满则创建线程执行任务;若满了则将任务放入等待队列;若等待队列已满且最大线程池未满,则创建新线程执行任务;若最大线程池已满,则执行拒绝策略。
  • ThreadPoolExecutor参数:corePoolSize(核心线程数)、maximumPoolSize(最大线程数)、keepAliveTime(存活时间)、unit(存活时间单位)、workQueue(任务队列)、threadFactory(线程工厂)、handler(拒绝策略)。
  • 线程池大小设置:需分析任务特性(CPU密集型或IO密集型),根据任务执行平均时长和CPU核心数等因素确定。
  • 拒绝策略:AbortPolicy(直接抛出异常)、CallerRunsPolicy(用调用者所在线程执行任务)、DiscardOldestPolicy(丢弃阻塞队列中最靠前的任务,执行当前任务)、DiscardPolicy(直接丢弃任务),也可自定义拒绝策略。

5. 常见线程安全的并发容器

常见线程安全的并发容器有ConcurrentHashMap、CopyOnWriteArrayList、CopyOnWriteArraySet等。

6. Atomic原子类

Java原子类位于java.util.concurrent.atomic包下,利用CAS(Compare and Swap)、volatile和native方法保证原子操作,避免synchronized的高开销,提升执行效率。

7. ConcurrentHashMap

  • 线程安全性:线程安全的Map容器。
  • JDK7原理:使用锁分段技术,每个数据段配置一把锁,提高性能,但Segment个数初始化后不能改变。
  • JDK8原理:使用Synchronized锁加CAS机制,结构上数组+链表+红黑树,优化了并发性能。

8. synchronized和volatile的区别

  • 本质:volatile保证变量从主存读取,synchronized锁定变量,只允许当前线程访问。
  • 使用范围:volatile仅用于变量,synchronized可用于变量、方法、类。
  • 功能:volatile仅实现变量修改可见性,不保证原子性;synchronized保证变量修改可见性和原子性。
  • 线程阻塞:volatile不会造成线程阻塞,synchronized可能会。
  • 编译器优化:volatile标记的变量不会被编译器优化,synchronized标记的变量可以被优化。

9. Java类加载过程

  • 加载:通过类的全限定名获取二进制流,转化为方法区运行时数据结构,生成Class对象。
  • 验证:验证字节流是否符合Class文件规范,包括文件格式验证、元数据验证、字节码验证等。
  • 准备:为类的静态变量分配内存并设置初始值。
  • 解析:将符号引用转换为直接引用。
  • 初始化:执行类中定义的Java程序代码。

10. 类加载器

  • 分类:引导类加载器(Bootstrap ClassLoader)加载Java核心类库,无法被继承;扩展类加载器(extension class loader)加载Java扩展库;系统类加载器(system class loader)根据Java应用的类路径加载Java类;用户自定义类加载器通过继承java.lang.ClassLoader类实现。
  • 加载机制:按需加载,初始化子类时父类先被加载,JVM启动时加载启动类。

11. Java内存分配与回收策略

  • 内存分配:栈区分为虚拟机栈和本地方法栈;堆区存放对象实例,分为新生代和老年代;方法区存储类信息等;程序计数器记录当前线程执行的字节码指令地址。
  • 回收策略:采用分代回收,新生代对象优先在Eden区分配,大对象直接进入老年代,长期存活的对象进入老年代。
  • Minor GC和Major GC:Minor GC发生在新生代,回收新生代垃圾;Major GC(full GC)发生在老年代,回收老年代和新生代垃圾,通常比Minor GC耗时更长。

12. 查看Java死锁及避免方法

  • 查看死锁:可使用jconsole、jstack等工具查看。
  • 避免死锁:注意加锁顺序,保证每个线程按同样顺序加锁;设置加锁时限,避免线程长时间等待;进行死锁检查,及时发现和解决死锁问题。

Java框架篇

1. SpringMVC工作流程

  • 用户发送请求至前端控制器DispatcherServlet。
  • DispatcherServlet调用HandlerMapping处理器映射器。
  • 处理器映射器找到对应的处理器,返回给DispatcherServlet。
  • DispatcherServlet调用HandlerAdapter处理器适配器。
  • 处理器适配器经过适配调用具体的处理器(Controller)。
  • Controller执行完成返回ModelAndView。
  • DispatcherServlet将ModelAndView返回给ViewReslover视图解析器。
  • 视图解析器解析后返回具体View。
  • 根据View进行渲染视图,响应用户。

2. Spring或SpringMVC中常用的注解

  • @Component:标识一个受Spring管理的组件。
  • @Controller:标识为一个表示层的组件。
  • @Service:标识为一个业务层的组件。
  • @Repository:标识为一个持久层的组件。
  • @Autowired:自动装配。
  • @Qualifier(“”):指定要装配的组件的id值。
  • @RequestMapping():完成请求映射。
  • @PathVariable:映射请求URL中占位符到请求处理方法的形参。

3. SpringMVC中返回JSON数据的方法

在项目中加入json转换的依赖(如jackson、fastjson、gson等),在请求处理方法上使用@ResponseBody注解。

4. Spring的理解

Spring是一个开源框架,为简化企业级应用开发而生,提供了IOC(控制反转)和AOP(面向切面编程)功能。IOC通过容器管理对象的创建和依赖注入,AOP用于实现横切关注点的功能,如日志记录、事务管理等。

5. Spring中常用的设计模式

  • 代理模式:若目标对象实现接口,Spring使用JDK的Proxy类代理;若未实现接口,使用CGLIB库生成目标类的子类代理。
  • 单例模式:在Spring配置文件中设置bean默认为单例模式。
  • 工厂模式:通过BeanFactory创建对象,解耦对象的创建和使用。

6. Spring循环依赖问题

Spring通过三级缓存解决循环依赖问题。在创建bean时,先将创建中的bean放入三级缓存,其他bean需要时可从缓存中获取,避免循环创建。但构造器注入属性无法解决循环依赖问题,因为实例化时属性未填充,无法提前暴露对象。

由于内容较多,以下将继续为你提炼补充该文档的部分内容,如果你需要更详细的章节提炼,请随时告诉我。

Java框架篇(续)

7. Spring bean的生命周期、注入方式和作用域(续)

  • 作用域(续):除了Singleton(单例)、Prototype(原型),还有Request(每次HTTP请求创建一个新的Bean实例)、Session(同一个HTTP Session共享一个Bean实例) 。

8. Spring的事务管理

  • 声明式事务管理:通过配置文件或注解来管理事务,如<tx:annotation-driven>配合@Transactional注解 ,声明式事务管理将事务管理与业务逻辑分离,方便维护。可以指定事务管理器,并通过Properties类型的transactionAttributes属性配置事务相关操作。
  • 编程式事务管理:在代码中显式调用beginTransaction()commit()等事务管理方法,这种方式对代码侵入性较大,实际应用中不如声明式事务管理常用。

9. MyBatis中#{}和${}的区别

  • #{}:MyBatis在处理#{}时,会将SQL中的#{}替换为?号,调用PreparedStatementset方法来赋值,能有效防止SQL注入,提高系统安全性。
  • ** ∗ ∗ : M y B a t i s 在处理 ‘ {}**:MyBatis在处理` MyBatis在处理{}时,会直接把${}`替换成变量的值,存在SQL注入风险,一般用于传入表名、字段名等,但使用时需谨慎。

10. MyBatis中一级缓存与二级缓存

  • 一级缓存:是SqlSession级别的缓存,默认开启。在同一个SqlSession中,执行相同的查询语句时,会直接从缓存中获取数据,而不再查询数据库。
  • 二级缓存:是NameSpace级别(Mapper)的缓存,多个SqlSession可以共享,使用时需要进行配置开启。开启二级缓存后,查询数据时会先从二级缓存中查找,若未找到再查询数据库。

11. MyBatis如何获取自动生成的(主)键值

在MyBatis的insert标签中,使用useGeneratedKeys="true"keyProperty="id"属性来获取自动生成的主键值。例如:<insert id="insertname" useGeneratedKeys="true" keyProperty="id"> insert into names (name) values (#{name}) </insert>,执行插入操作后,生成的主键值会自动赋值给对应的Java对象的id属性。

12. 简述MyBatis的动态SQL,列出常用的6个标签及作用

  • 动态SQL:MyBatis的动态SQL基于功能强大的OGNL表达式,主要用于解决查询条件不确定的情况,在程序运行期间,根据提交的条件动态完成查询。
  • 常用标签
    • <if>:进行条件判断,根据条件是否成立决定SQL片段是否包含在最终的SQL语句中。
    • <where>:在<if>判断后的SQL语句前面添加WHERE关键字,并处理SQL语句开始位置的AND或者OR的问题,避免出现多余的关键字。
    • <trim>:可以在SQL语句前后添加指定字符或者去掉指定字符,灵活调整SQL语句的格式。
    • <set>:主要用于修改操作时处理逗号问题,在更新语句中,会自动去掉多余的逗号。
    • <choose><when><otherwise>:类似于Java中的switch语句,在多个条件中选择其一,根据条件的优先级依次判断,满足条件则执行对应的SQL片段。
    • <foreach>:用于遍历集合,在插入或更新操作中,实现批量操作,例如批量插入数据时,循环遍历集合生成多条插入语句。

13. MyBatis如何完成MySQL的批量操作

通过<foreach>标签实现MySQL的批量操作。在<insert>标签中,使用<foreach>遍历集合,将集合中的元素按照指定的格式插入到数据库中。例如:

<insert id="insertBatch">insert into tbl_employee(last_name,email,gender,d_id) values<foreach collection="emps" item="curr_emp" separator=",">(#{curr_emp.lastName},#{curr_emp.email},#{curr_emp.gender},#{curr_emp.dept.id})</foreach>
</insert>

14. Spring Boot框架

  • 框架概述:Spring Boot是Spring开源组织下的子项目,是Spring组件一站式解决方案,主要简化了使用Spring的难度,减少了繁重的配置,提供了各种启动器,开发者能快速上手。
  • 优点:独立运行,可直接打包成可执行的JAR文件;启动器自动依赖其他组件,减少了Maven的配置;能根据当前类路径下的类、JAR包来自动配置Bean;无需XML配置文件,借助条件注解完成所有配置工作。
  • 核心注解@SpringBootApplication是Spring Boot的核心注解,组合包含了@SpringBootConfiguration(实现配置文件的功能)、@EnableAutoConfiguration(打开自动配置的功能,也可关闭某个自动配置选项)、@ComponentScan(扫描指定包及其子包下的组件)。
  • 自动配置原理:基于@EnableAutoConfiguration@Configuration@ConditionalOnClass等注解实现。根据类路径下是否存在某个类来自动配置Bean,例如添加一个启动器就能拥有相应的功能,无需额外配置。
  • 配置文件:包括application.propertiesbootstrap.propertiesbootstrap由父ApplicationContext加载,比application优先加载,且里面的属性不能被覆盖,常用于连接配置中心、设置固定属性或加密/解密场景。可通过不同的配置文件实现多环境配置,运行时指定具体的配置文件。

15. Spring Boot和Spring Cloud的关系

Spring Boot是一个快速开发框架,提供了快速配置和开发单个微服务的能力;Spring Cloud是一个基于Spring Boot实现的开发工具,关注全局的服务治理框架,很多集成方案基于Spring Boot实现,必须基于Spring Boot开发项目。Spring Cloud依赖Spring Boot提供的基础能力,如自动配置、内嵌服务器等,来构建分布式系统。

16. Spring Cloud常用组件及作用

  • Eureka:服务注册与发现组件,服务提供者将自己注册到Eureka Server,服务消费者从Eureka Server获取服务列表,实现服务的自动注册和发现。
  • Gateway:作为网关,是分布式系统统一的出入口,进行服务路由、统一鉴权、请求过滤、负载均衡等操作。
  • OpenFeign:作为远程调用的客户端,实现服务之间的远程调用,通过注解方式定义接口来调用其他服务的API。
  • Sentinel:实现系统的熔断限流,保护系统在高并发情况下的稳定性,防止因流量过大导致系统崩溃。
  • Sleuth:实现服务的链路追踪,通过生成唯一的Trace ID和Span ID来追踪请求在各个服务之间的调用路径和耗时,便于排查问题和优化系统性能。

17. Nacos作用以及注册中心的原理

  • Nacos作用:Nacos(Dynamic Naming and Configuration Service)是一个集服务注册中心和配置中心于一体的平台,为服务提供注册、发现、配置管理等功能,支持多种框架和语言。
  • 注册中心原理:Nacos注册中心分为server与client。server采用Java编写,为client提供注册服务、保存并提供Client配置信息、向Client提供服务列表等功能;client负责注册自身服务、获取服务列表、获取配置信息、维持心跳信息等。Nacos通过心跳机制检查服务实例的健康状态,若实例不健康则剔除。服务变更时,通过长轮询订阅服务,client拉取服务信息。

18. Feign工作原理

  • 首先通过@EnableFeignClients注解开启对FeignClient的扫描加载处理。
  • 根据Feign的开发规范,定义接口并加@FeignClient注解。
  • 当程序启动时,会进行包扫描,扫描到带有@FeignClient注解的类,并将这些信息注入Spring IOC容器。
  • 接口中的方法被调用时,通过JDK的代理方式生成具体的代理对象。Feign会为每个接口方法创建一个RequestTemplate,确定请求需要的全部信息,如请求参数名、请求方法等。
  • 最后根据RequestTemplate生成Request,基于负载均衡、重试器以及不同的HTTP请求框架,发送HTTP请求。

Mysql数据库篇

1. Select语句完整的执行顺序

  • from子句:组装来自不同数据源的数据,确定数据的来源表或视图。
  • where子句:基于指定的条件对记录行进行筛选,过滤掉不符合条件的数据行。
  • group by子句:对数据进行分组,将满足相同条件的数据分为一组。
  • having子句:筛选分组,对分组后的结果进行进一步筛选,只有满足having条件的分组才会被保留。
  • select子句:选择要查询的列,可以是具体的列名,也可以使用通配符*表示选择所有列。
  • order by子句:对结果集进行排序,可以按照升序(ASC)或降序(DESC)排列。

2. MySQL事务

  • 事务概念:事务是一组操作的集合,这些操作要么全部完成,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,保证数据的一致性和完整性。
  • 事务的基本要素(ACID)
    • 原子性(Atomicity):事务中的所有操作要么全部成功,要么全部失败,不可分割。
    • 一致性(Consistency):事务执行前后,数据库的完整性约束没有被破坏,数据从一个一致性状态转换到另一个一致性状态。
    • 隔离性(Isolation):多个事务并发执行时,一个事务的执行不能被其他事务干扰,各个事务之间相互隔离。
    • 持久性(Durability):事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚。
  • MySQL事务隔离级别
    • 读未提交(read - uncommitted):允许读取未提交的数据,可能会出现脏读、不可重复读和幻读问题。
    • 读提交(read - committed):只能读取已提交的数据,可避免脏读,但仍可能出现不可重复读和幻读。
    • 可重复读(repeatable - read):保证在同一个事务中多次读取同一数据时,结果一致,可避免脏读和不可重复读,但仍可能出现幻读。
    • 串行化(serializable):最高的隔离级别,事务串行执行,可避免所有并发问题,但性能较低。

3. MyISAM和InnoDB的区别

  • 事务支持:MyISAM不支持事务;InnoDB支持事务,提供了更好的数据一致性和完整性保障,适合处理需要事务支持的业务场景,如银行转账、电商订单处理等。
  • 锁机制:MyISAM使用表锁,对表进行操作时会锁定整个表;InnoDB支持表锁和行锁,行锁可以提高并发性能,减少锁冲突,适合高并发的应用场景。
  • 文件存储:MyISAM存储为3个文件;InnoDB存储为1个文件,InnoDB的文件存储方式在数据管理和维护上相对更方便。
  • 外键支持:MyISAM不支持外键;InnoDB支持外键约束,用于维护表与表之间的数据一致性和完整性,确保相关数据的准确性和一致性。

4. 悲观锁和乐观锁的实现

  • 悲观锁:悲观锁认为数据在并发操作时很可能会发生冲突,所以在操作数据前先获取锁,锁定数据,防止其他线程修改。在MySQL中,使用select...for update语句实现悲观锁,例如:select price from item where id = 100 for update,该语句会锁定查询到的行,确保在当前事务处理期间,其他事务无法修改这些行的数据。使用悲观锁时必须确定走了索引,避免全表扫描,否则会锁住整个数据表。
  • 乐观锁:乐观锁认为数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测。如果发现冲突了,则返回错误信息,让用户决定如何去做。利用数据版本号(version)机制是乐观锁最常用的一种实现方式,一般通过为数据库表增加一个数字类型的“version”字段,当读取数据时,将version取出,数据每更新一次,对此version值 + 1。当提交更新时,判断数据库表对应记录的当前版本信息与第一次取出来的version值进行比对,如果相等,则予以更新,否则认为是过期数据,返回更新失败。

5. 聚簇索引与非聚簇索引区别

  • 数据结构:聚簇索引和非聚簇索引都是B + 树的数据结构。
  • 数据存储方式:聚簇索引将数据存储与索引放到了一块,并且是按照一定的顺序组织的,找到索引也就找到了数据,数据的物理存放顺序与索引顺序一致;非聚簇索引的数据和索引是分开存储的,通过索引需要二次查询才能获取数据。
  • 查询效率:查询通过聚簇索引可以直接获取数据,相比非聚簇索引需要第二次查询,效率要高;聚簇索引对于范围查询的效率很高,因为其数据是按照大小排列的;非聚簇索引适合用在查询条件不固定,需要频繁进行随机查询的场景。
  • 维护成本:聚簇索引维护索引很昂贵,特别是插入新行或者主键被更新导致要分页(pagesplit)时,会移动大量数据,可能造成碎片;非聚簇索引的维护成本相对较低。

6. 什么情况下mysql会索引失效

  • where后面使用函数:例如explain SELECT * from test_slow_query where age = 20explain SELECT * from test_slow_query where age + 10 = 30,后者在where条件中使用了函数,会导致索引失效。
  • 使用or条件:当or条件中的字段没有全部建立索引时,可能导致索引失效,如explain SELECT * from test_slow_query where NAME = '吕布' or name = "aaa"
  • 模糊查询%放在前边explain SELECT * from test_slow_query where NAME like '%吕布',这种情况下索引无法有效利用,会导致全表扫描。
  • 类型转换:如果查询条件中的字段类型与索引定义的类型不一致,会发生隐式类型转换,导致索引失效,如explain SELECT * from test_slow_query where NAME = 11(假设NAME字段为字符串类型)。
  • 组合索引(最佳左前缀匹配原则):组合索引使用时需遵循最佳左前缀匹配原则,否则会导致部分索引失效,如建立了(a,b,c)组合索引,查询时where b = 1 and c = 1无法利用该组合索引的全部字段。

7. B + tree与B - tree区别

  • 结构区别:B - tree的节点既存储数据又存储索引,数据指针指向实际的数据块;B + tree的非叶子节点只存储索引,不存储数据,数据全部存储在叶子节点中,叶子节点之间通过双向链表连接。
  • 查询效率:B + tree的查询效率更高,因为其所有数据都在叶子节点,且叶子节点有序排列,适合范围查询和全表扫描;B - tree在范围查询时效率相对较低,因为需要遍历更多的节点。
  • 节点存储内容:B - tree的一个节点可以存储多个元素,并且这些元素也排序了;B + tree的叶子节点存储了所有的数据,非叶子节点用于索引查找,节点中的元素也排序了,这种结构使得B + tree在查找数据时可以更快地定位到目标数据。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com