首页 > 编程语言 >Java面试相关问题

Java面试相关问题

时间:2024-03-22 10:31:01浏览次数:33  
标签:Java 索引 Spring 查询 面试 bean 相关 方法 节点

 一.MySql篇

1优化相关问题

1.1.MySql中如何定位慢查询?


 慢查询的概念:在MySQL中,慢查询是指执行时间超过一定阈值的SQL语句。这个阈值是由long_query_time参数设定的,它的默认值是10秒1。也就是说,如果一条SQL语句的执行时间超过了long_query_time所设定的时间,那么这条SQL语句就被认为是慢查询。

现在的问题就是:出现页面加载过慢,响应时间过长。我怎么确定就是我sql的问题呢?就算是sql的问题,我应该怎么找出执行慢的那条sql语句呢?

方案一:使用开发工具

以Skywalking为例。这个工具,可以直观看到每个接口的执行时间。还可以追踪进接口,详细的看耗时情况,其中也包含了sql的耗时。

方案二:使用MySql自带的慢日志

简单来说,这个日志记录了执行时间较长的sql。

总结:

1.2.索引相关概念


基础概念:        

在MySQL中,索引是一种数据结构,用于加快数据库查询的速度和性能。索引可以帮助MySQL快速定位和访问表中的特定数据,就像书籍的索引一样,通过存储指向数据行的指针,可以快速查找到需要的页面。

底层数据结构 (B+树):

        1.磁盘读写代价更低:非叶子节点不存放数据,只存储指针,相对来说存储压力低。数据只存储在叶子节点,在查询比对的时候,就不会把非叶子节点上的数据也加载出来了。

        2.查询效率稳定:因为数据都存储在非叶子节点,在查询时都要从根节点开始对比。最终到叶子节点获取数据。

        3.便于扫库和区间查询:叶子节点之间采用双向指针。在范围查询时更加方便。比如说:我们现在要查找索引为6~34区间的数据。先从根节点出发找到比38小的16,再从16往左找到叶子节点6,由于叶子节点之间有双向指针,因此6~34区间的数据都能获取!(这个区间内的数据不需要再从根节点再次查找)

总结:

1.什么是索引:

        索引在项目中还是比较常见的,它是帮助MySQL 高效获取数据的数据结构,主要是用来提高数据检索的效率,降低数据库的IO 成本,同时通过索引列对数据进行排序,降低数据排序的成本,也能降低了CPU 的消耗。 2.索引底层的数据结构:         MySQL的默认的存储引擎 InnoDB 采用的 B+ 树的数据结构来存储索引,选择B+ 树的主要的原因是:第一阶数更多,路径更短,第二个磁盘读写代价B+ 树更低,非叶子节点只存储指针,叶子阶段存储数据,第三是 B+ 树便于扫库和区间查询,叶子节点是一个双向链表。 3.B树和B+树的区别:         第一:在B 树中,非叶子节点和叶子节点都会存放数据,而 B+ 树的所有的数据都会出现在叶子节点,在查询的时候,B+ 树查找效率更加稳定。 第二:在进行范围查询的时候, B+ 树效率更高,因为 B+ 树都在叶子节点存储,并且叶子节点是一个双向链表。

1.3.聚簇索引和非聚簇索引


这里的主键id就是聚集索引,每个叶子节点存放的数据,就是当前叶子节点主键id所对应的一行数据!

假如我们这里把name字段也添加了索引,它就是非聚集索引 (二级索引)。它的叶子节点所存储的数据,就是当前name对应的主键id。比如说叶子节点Arm,存储的数据就是:10。

1.4回表查询


现在我们有一条sql语句:select * from user where name = 'Arm'

由于我们给name字段添加了索引。这里的执行顺序就是:

1.先去二级索引里面找Arm,先跟根节点Lee比对,A在L的左边,找到Geek,A在G的左边。找到叶子节点Arm,该叶子节点存储的数据是Arm的主键id:10。

2.因为这里我要获取Arm的所有信息 * 。因此,二级索引无法提供完整信息,我还要根据找到的主键值10,去聚集索引里面查询。

3.重复类似过程一,从聚集索引里面找到主键id = 10的叶子节点。该叶子节点存储的数据,就是id = 10 的所有信息!

        这整个过程就是回表查询

总结:

1.聚集索引和非聚集索引

        聚簇索引主要是指数据与索引放到一块,B+ 树的叶子节点保存了整 行数据,有且只有一个,一般情况下主键在作为聚簇索引的。         非聚簇索引值的是数据与索引分开存储,B+ 树的叶子节点保存对应的主键,可以有多个,一般我们自己定义的索引都是非聚簇索引 2.回表查询         回表查询跟聚簇索引和非聚簇索引是有关系的,回表的意思就是通过二级索引找到对应的主键值,然后再通过主键值找到聚集索引中所对应的整行数据,这个过程就是回表。

1.5.覆盖索引


MySql超大分页处理问题:

解决方案:

先根据id排序并从9000000条数据里面获取10条。这里根据id排序并返回id走的是覆盖索引。

再跟之前的表做关联,做一个等价查询。这样性能就有所提升了。

第一条sql是把9000010条数据全部提交给server层,然后再根据limit的第一个参数丢弃前9000000条数据,只要10条数据。

而第二条sql,是把9000010条id给server操作,相比来说就优化了。

总结:

1.覆盖索引:

        覆盖索引是指select 查询语句使用了索引,在返回的列,必须在索引中全部能够找到,如果我们使用id 查询,它会直接走聚集索引查询,一次索引扫描,直接返回数据,性能高。         如果按照二级索引查询数据的时候,返回的列中没有创建索引,有可能会触发回表查询,尽量避免使用select * ,尽量在返回的列中都包含添加索引的字段。 2.MySql超大分页处理         超大分页一般都是在数据量比较大时,我们使用了limit 分页查询,并且需要对数据进行排序,这个时候效率就很低,我们可以采用覆盖索引和子查询来解决先分页查询数据的 id 字段,确定了 id 之后,再用子查询来过滤,只查询这个id列表中的数据就可以了因为查询id 的时候,走的覆盖索引,所以效率可以提升很多。

1.6.索引创建的原则


总结:

        一般表中的数据要超过10万以上,我们才会创建索引,并且添加索引的字段是查询比较频繁的字段,一般也是像作为查询条件,排序字段或分组的字段这些。         还有就是,我们通常创建索引的时候都是使用复合索引来创建,一条sql 的返回值,尽量使用覆盖索引,如果字段的区分度不高的话,我们也会把它放在组合索引后面的字段。如果某一个字段的内容较长,我们会考虑使用前缀索引来使用,当然并不是所有的字段都要添加索引,这个索引的数量也要控制,因为添加索引也会导致新增改的速度变慢。

1.7.索引失效的情况


这是正常查询情况,满足最左前缀,先查有先度高的索引。

注意这里最后一种情况,这里和上面只查询 name = '小米科技' 的命中情况一样。说明索引部分丢失!

二.框架篇

       1.Spring框架

1.1.Spring框架中的bean默认情况下是单例的吗?


 Spring框架中的bean默认情况下是单例的。Spring中有一个注解@Scope,这是用来设置bean的情况。默认情况下设置为singleton(单例的)

1.2.Spring框架中的单例bean是线程安全的吗?


 

简单来说就是:判断当前成员变量能不能修改。如果是int这种可修改的类型,线程就不是安全的。

如果是,Service、DAO这些无状态类 (没有什么可变状态)就算是线程安全的。

总结:

        不是线程安全的,是这样的:         当多用户同时请求一个服务时,容器会给每一个请求分配一个线程,这是多个线程会并发执行该请求对应的业务逻辑(成员方法),如果该处理逻辑中有对该单列状态的修改(体现为该单例的成员属性),则必须考虑线程同步问题。        Spring框架并没有对单例bean 进行任何多线程的封装处理。关于单例 bean的线程安全和并发问题需要开发者自行去搞定。         比如:我们通常在项目中使用的Spring bean都是不可可变的状态 (比如Service类和DAO 类 ) ,所以在某种程度上说 Spring 的单例 bean是线程安全的。如果你的bean有多种状态的话(比如 View Model对象),就需要自行保证线程安全。最浅显的解决办法就是将多态bean的作用由 “ singleton ”变更为“prototype”。

1.3.什么是AOP?项目中有没有使用AOP?


AOP的概念及常见使用场景: 总结:                  aop是面向切面编程,在 spring 中用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取公共模块复用,降低耦合,一般比如可以做为公共日志保存,事务处理等。         实际项目中使用AOP的例子: 在后台管理系统中,就是使用 aop 来记录了系统的操作日志 主要思路是这样的,使用 aop 中的环绕通知 + 切点表达式,这个表达式就是要找到要记录日志的方法,然后通过环绕通知的参数获取请求方法的参数,比如类信息、方法信息、注解、请求方式等,获取到这些参数以后,保存到数据库。

1.4.Spring中事务是如何实现的?

这里的"保存用户"方法,就是我们要加事务的方法。在该方法上添加@Transactional注解。

总结:

        声明式事务管理实际上是基于Spring的AOP(面向切面编程)机制实现的。当你在方法上使用@Transactional注解时,Spring会在运行时创建一个代理对象,这个代理对象会在方法调用前后插入事务管理的代码,从而实现事务的自动管理。

        具体来说,当Spring容器在运行时遇到带有@Transactional注解的方法时,它会创建一个代理对象来拦截这个方法。在代理对象拦截方法调用时,Spring会在方法调用前后分别插入开始事务和结束事务的代码。如果方法执行过程中抛出异常,Spring会根据异常类型决定是否回滚事务。

        因此,虽然在使用声明式事务管理时,开发者不需要自己编写AOP代码,但是Spring仍然使用了AOP技术来实现事务管理。这也是为什么有时候我们会说声明式事务管理是基于AOP的。

1.5.Spring中事务失效的场景


 

这种情况下,自己把异常处理了,导致@Transactional没有发现异常,事务没有回滚。

Spring默认只会回滚非检查异常也就是runtime异常。而这里的FileNotFound是一个检查异常,并不能被捕获。

Spring为方法创建代理,添加事务通知,前提条件都是该方法是public修饰的!

1.6.Bean的生命周期


1.BeanDefinition

2.构造函数

在此期间,调用Bean的构造函数,实例化对象 (但是还未赋值!)

3.依赖注入

Spring容器会将Bean的属性设置为Bean定义中指定的值。这个过程也被称为依赖注入,因为Spring容器会自动寻找并注入Bean所依赖的其他Bean。

4.Aware接口

用于增强Bean的功能

如果Bean实现了以Aware结尾的接口,就要重写里面的方法。图中三个接口,就是分别用于在Bean的初始化过程中,用于获取:Bean的名字、Bean的工厂、容器的上下文对象(Spring容器本身)。

5.BeanPostProcessor#before

bean的后置处理器,在初始化方法调用之前执行。

6.初始化方法

        1.InitalizingBean接口,实现了该接口,就要实现里面的方法。而在这一步就会执行重写方法。

        2.自定义init:在bean中某个方法上标注了@PostConstruct注解。就会在这一步执行这个方法。

7.BeanPostProcessor#before

bean的后置处理器,在初始化方法调用之后执行。

当一个类的功能被增强了使用到了AOP,大概率就是使用后置处理器被增强的。

  

8.销毁Bean

如果在哪个方法上标注了@PreDestroy方法,Spring容器在关闭前就会调用该方法。

注:

1.Bean的创建和初始化是分开的,第2步是创建bean,3-7是初始化赋值

2.第5步和第7步的两个后置处理器。都是某个类实现了BeanPostProcessor接口,所重写的两个方法。分别在初始化方法前后执行。

测试代码:

第一个类User类,作为我们测试的Bean

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

@Component
public class User implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean {

    public User() {
        System.out.println("1.User的构造方法执行了.........");
    }

    private String name;

    @Value("张三")
    public void setName(String name) {
        System.out.println("2.依赖注入执行了..........");
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("3.BeanNameAware的实现方法执行了.......");
    }

    @Override
    public void setBeanName(String s) {
        System.out.println("3.BeanNameAware的实现方法执行了.......");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("3.ApplicationContextAware的实现方法执行了.......");
    }

    @PostConstruct
    public void init() {
        System.out.println("5.自定义初始化方法执行了..........");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("5.InitializingBean的实现方法执行了..........");
    }

    @PreDestroy
    public void destroy(){
        System.out.println("7.destroy方法执行了.........");
    }
}

第二个类:实现了BeanPostProcessor重写了其中方法的类。里面是两个后置处理器。

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (beanName.equals("user")) {
            System.out.println("4.postProcessBeforeInitialization方法执行了 -> user对象初始化方法之前执行");
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (beanName.equals("user")) {
            System.out.println("6.postProcessAfterInitialization方法执行了 -> user对象初始化方法之后执行");
        }
        return bean;
    }
}

执行结果

destroy方法要在容器关闭时执行

总结:

        1.首先会通过一个非常重要的类,叫做BeanDefinition获取bean的定义信息, 这里面就封装了bean的所有信息,比如,类的全路径,是否是延迟加载,是否是单例等等这些信息。        

        2.在创建bean的时候,第一步是调用构造函数实例化bean

        3.第二步是bean的依赖注入,比如一些set方法注入,像平时开发用的@Autowire都是这一步完成。

        4.第三步是处理Aware接口,如果某一个bean实现了Aware接口就会重写方法执行。

        5.第四步是bean的后置处理器BeanPostProcessor,这个是前置处理器。

        6.第五步是初始化方法,比如实现了接口InitializingBean或者自定义了方init-method标签或@PostContruct。

        7.第六步是执行了bean的后置处理器BeanPostProcessor,主要是对bean进行增强,有可能在这里产生代理对象。

        8.最后一步是销毁bean。

标签:Java,索引,Spring,查询,面试,bean,相关,方法,节点
From: https://blog.csdn.net/qq_64064246/article/details/136775826

相关文章

  • JAVA基本数据类型转换、关键字、转义字符
    基本数据类型转换自动类型转换:容量小的类型自动转换成容量大的数据类型byte,short,它们在计算时会转换int类型如果把int转换成float值,或者long转换成double值,不需要强制转换,但可能丢失精度publicclassMain{publicstaticvoidmain(String[]args){byteb......
  • 深入解析Mybatis-Plus框架:简化Java持久层开发(十二)
    ......
  • Java使用数据库连接池
    一、原生JDBC操作数据库的步骤(1)加载数据库驱动。(2)获取数据库连接。(3)预编译SQL语句。(4)执行SQL。(5)获取结果集。(6)释放资源。示例代码如下:publicclassJDBCTest{    publicstaticvoidmain(String[]args)throwsClassNotFoundException,SQLException......
  • Day01 文学生也想学java之今天我也许学能学会Markdown
    Day01文学生也想学java之今天我也许学能学会Markdown1.标题一级标题:#+(空格)+标题内容二级标题:##+(空格)+标题内容......(以此类推)2.字体helloworld!:前后两个*helloworld!:前后一个*helloworld!:前后三个*helloworld!:前后两个~3.引用这是一句引用:引用=>+(空格)4.分割线---+......
  • 一线大厂面试真题——fail-safe机制与fail-fast机制分别有什么作用
    fail-safe和fail-fast,是多线程并发操作集合时的一种失败处理机制。Fail-fast:表示快速失败,在集合遍历过程中,一旦发现容器中的数据被修改了,会立刻抛出ConcurrentModificationException异常,从而导致遍历失败,像这种情况(贴下面这个图)。定义一个Map集合,使用Iterator迭代器进行数......
  • 关于小米/红米手机 root 相关说明
    关于小米/红米手机root相关说明相关网站和软件获取网址:小米解锁官网:http://www.miui.com/unlock/index.html解锁常见问题说明:https://web.vip.miui.com/page/info/mio/mio/detail?postId=4378807&app_version=dev.20051小米手机rom第三方下载地址:https://roms.miuier.com......
  • 毕业设计课题:实验室课程管理系统,基于java+SSM+mysql
          一、前言介绍     如今互联网发展迅猛,大量的信息都是通过网络这一渠道来传播,所以利用网络渠道来传播知识是非常有前景的。线上管理系统的主要目的是对实验室课程信息进行更有效的管理,光靠现有的管理方式是远远不够的,因此开发实验室课程管理系统是有必要的......
  • 毕业设计课题:少儿编程管理系统,基于java+SSM+mysql
          一、前言介绍     21世纪,我国早在上世纪就已普及互联网信息,互联网对人们生活中带来了无限的便利。像大部分的企事业单位都有自己的系统,由从今传统的管理模式向互联网发展,如今开发自己的系统是理所当然的。那么开发少儿编程管理系统意义和用处有哪些呢? ......
  • Jackson进行JSON序列化/反序列化添加Java 8的日期和时间库支持
     添加依赖包<!--Jackson进行JSON序列化/反序列化添加Java8的日期和时间库支持--> <dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-jsr310</artifactId> <version>2.13.0</version> ......
  • 基于Springboot的瑜伽馆管理系统的设计与实现(有报告)。Javaee项目,springboot项目。
    演示视频:基于Springboot的瑜伽馆管理系统的设计与实现(有报告)。Javaee项目,springboot项目。项目介绍:采用M(model)V(view)C(controller)三层体系结构,通过Spring+SpringBoot+Mybatis+Vue+Maven+Layui+Elementui来实现。MySQL数据库作为系统数据储存平台,实现了基于B/S结构......