尚硅谷第一季经典Java面试题(不难,进来测测自己基础哦)

JavaSE面试题

设计模式

单例设计模式

Singleton:在Java中即指单例设计模式,是软件开发最常用的设计模式之一

单:唯一

例:实例

单例设计模式,即某个类在整个系统中只能有一个实例对象可被获取和使用的代码设计模式。例如:代表JVM运行环境的Runtime类

要点:
一是某个类只能有一个实例

我们把这个类的构造器进行私有化处理,那么就能保证其他类不可能创建这个类的实例,就能保证单例类只会有一个实例。

二是他必须自行创建实例

创建出实例之后需要保存这个实例,那么就需要创建一个该类的静态变量来保存这个唯一的实例,因为静态变量能保证这个变量是类唯一的且不需要手动创建这个类的实例(实际上第一点已经限制了我们无法手动创建单例类的类实例)

三是它必须自行向整个系统提供这个实例

前面两点已经保证了这个单例类只会创建一个实例,第三点是为了保证单例模式的使用。

对外提供获取该类实例对象的方式

  • 直接暴露,这是饿汉式的实现方式
  • 用静态变量的get方法获取,这是懒汉式的实现方式
几种常见形式
饿汉式:直接创建对象,不存在线程安全问题

饿汉式会在类初始化时直接创建实例对象,而不管之后是否会用到这个对象。

  1. 直接实例化饿汉式(简洁直观)
  2. 枚举式 (最简洁)
  3. 静态代码块饿汉式(适合复杂实例化)

直接实例化饿汉式(简洁直观)

public class Singleton1 {
    /**
     * 1、构造器私有化
     * 2、自行创建,并且用静态变量保存
     * 3、向外提供实例
     * 4、强调这是一个单例,我们可以用final修改
     */
    private Singleton1() {
    }
    public static final Singleton1 INSTANCE = new Singleton1();
}

枚举式 (最简洁)

public enum  Singleton2 {
    /**
     * 枚举类型没有构造器,不能初始化
     * 枚举类型:表示该类型是有限的几个,单例模式我们可以手动设置为一个
     */
    INSTANCE
}

静态代码块饿汉式(适合复杂实例化)

public class Singleton3 {
    public static final Singleton3 INSTANCE;
    private String info;
	/**
     *  静态代码块
     */
    static {
        try {
            INSTANCE = new Singleton3("123");
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
    private Singleton3(String info) {
        this.info = info;
    }
}
懒汉式:延迟创建对象

线程不安全(使用于单线程)
线程安全(使用于多线程)
静态内部类模式 (适用于多线程)

线程不安全(使用于单线程)

public class Singleton4 {
    /**
     * 1、构造器私有化
     * 2、用一个静态变量保存这个唯一的实例
     * 3、提供一个静态方法,获取这个实例对象
     */
    static Singleton4 instance;
    private Singleton4() {}

    public static Singleton4 getInstance() {
            if (instance == null) {//可能会有多个线程同时进行判断,然后进入if方法体
                instance = new Singleton4();
            }
            return instance;

    }
}

线程安全(使用于多线程)

public class Singleton5 {
    static Singleton5 instance;
    private Singleton5() {}
	
    public static Singleton5 getInstance() {
        if (instance == null) {
            synchronized (Singleton5.class) {//类锁(静态方法),保证一次只有一个线程执行方法体
                if (instance == null) {
                    instance = new Singleton5();
                }
                return instance;
            }
        }
        return instance;
    }
}

静态内部类模式 (适用于多线程)

public class Singleton6 {
    /**
    * 静态内部类不会自动创建,不会随着外部类的加载初始化而初始化,他是要单独去加载和实例化的。只有内部类被加载和初始化时,才会创建INSTANCE实例对象,所以是线程安全的(类的加载只会进行一次)。
    */
    private Singleton6(){}
    public static class Inner{
        private static final Singleton6 INSTANCE = new Singleton6();
    }
    public static Singleton6 getInstance() {
        return Inner.INSTANCE;
    }
}

类初始化实例初始化

类初始化过程

  1. 一个类要创建实例需要先加载并初始化该类

    • main方法所在的类需要先加载和初始化,也就是说我们执行一个类的main方法时,main方法所在类会首先进行加载和初始化。
  2. 一个子类要初始化时需要先初始化其父类

  3. 一个类的初始化过程就是执行 clinit 方法(这个方法是编译器自动生成的一个方法,专门用来进行类初始化的)的过程

    • clinit 方法由静态(类)变量显式赋值代码和静态代码块组成

    • 类变量显式赋值代码和静态代码块代码是从上到下按代码顺序执行

    • clinit 方法只调用一次,因为类初始化过程就一次。

实例初始化过程

  • 实例初始化过程就是执行 init() 方法的过程
    • init() 方法由非静态(实例)变量显式赋值代码和非静态代码块以及对应构造器代码组成
    • 非静态(实例)变量显式赋值代码和非静态代码块也是从上到下按顺序执行,而对应构造器的代码最后执行
    • 每次创建实例对象,调用对应构造器,都会执行其对应的init方法
    • init方法的首行是super()和super(实参列表) ,即子类所对应的父类的init方法
    • init()方法可能重载有多个,有几个构造器就有几个

方法的重写Override

对象的多态性
  • 子类如果重写了父类的方法,那么通过子类对象调用的一定是子类重写过的方法
  • 非静态方法默认的调用对象是this
  • this对象在构造器或者说方法中就是正在创建的对象(尽管这个对象并没有真正的创建出来)

但是被final关键字和static关键字以及private关键字(包括所有子类不可见方法)修饰的方法不可以被重写。

Father.java

/**
 * 父类初始化<clinit>
 * 1、j = method()
 * 2、 父类的静态代码块
 *
 * 父类实例化方法:
 * 1、super()(最前)
 * 2、i = test() (9)这个方法被子类重写了且此时是子类实例的初始化过程,this指向子类对象,所以执行的子类的test方法
 * 3、父类的非静态代码块 (3)
 * 4、父类的无参构造(最后)(2)
 *
 * 非静态方法前面其实有一个默认的对象this
 * this在构造器或<init> 中表示的是正在创建的对象,因为咱们这里是正在创建Son对象,所以
 * test()执行的就是子类重写的代码(面向对象多态)
 */
public class Father {
    private int i = test();
    private static int j = method();

    static{
        System.out.println("(1)");
    }
    Father() {
        System.out.println("(2)");
    }
    {
        System.out.println("(3)");
    }
    public int test(){
        System.out.println("(4)");
        return 1;
    }
    public static int method() {
        System.out.println("(5)");
        return 1;
    }
}

Son.java

/**
 * 子类的初始化<clinit>
 * 1、j = method()
 * 2、子类的静态代码块
 *
 * 先初始化父类 (5)(1)
 * 初始化子类 (10) (6)
 *
 * 子类实例化方法:
 * 1、super()(最前
 * 2、i = test() (9)
 * 3、子类的非静态代码块 (8)
 * 4、子类的无参构造(最后)(7)
 * @author gcq
 * @Create 2020-09-25
 */
public class Son extends Father {
    private int i = test();
    private static int j = method();
    static {
        System.out.println("(6)");
    }
    Son() {
        super();
        System.out.println("(7)");
    }
    {
        System.out.println("(8)");
    }
    public int test(){
        System.out.println("(9)");
        return 1;
    }
    public static int method() {
        System.out.println("(10)");
        return 1;
    }

    public static void main(String[] args) {
        Son son = new Son();//(5)(1)(10)(6)(9)(3)(2)(9)(8)(7)
        System.out.println();
        Son son1 = new Son();
    }//(9)(3)(2)(9)(8)(7)

方法参数传递机制

java中所有有参方法的参数传递机制都是值传递,而不存在引用传递。基本数据类型传递的是数据值,引用数据类型传递的是其地址值。

引用类型传递时,不可变类的修改会创建新对象,比如String、包装类等都具有对象的不可变性,如果我们传递这些类型的对象作为参数的话,如果修改其值,那么会在堆中创建它们的新实例来存储新值。因为它们是不可变类型,不能修改其原本内容。

递归与迭代

关于需要不断重复执行同一过程的计算,我们可以考虑递归和迭代。
方法调用自身称为递归,利用变量的原值推出新值然后不断对新值循环进行判断计算称为迭代。
递归
优点:大问题转化为小问题,可以减少代码量,同时代码精简,可读性好;
缺点:递归调用浪费了空间,而且递归太深容易造成堆栈的溢出。
迭代
优点:代码运行效率好,因为时间复杂度为 O(n),而且没有额为空间的开销;
缺点:代码不如递归简洁。

局部变量与成员变量的区别

  1. 声明的位置
    • 局部变量:方法体 { } 中、代码块 { } 中、形参
    • 成员变量:类中的方法体之外
      • 类变量 :用static修饰符修饰的成员变量
      • 实例变量:没有static修饰的成员变量
  2. 修饰符
    • 局部变量:final(局部变量的修饰符只有这一个,表示其是一个常量)

    • 成员变量:public、protected、private、final、static、volatile、transient

  3. 值存储的位置
    • 局部变量:栈:指的是虚拟机栈,虚拟机栈用于存储局部变量表,局部变量表存放了编译器可知长度的各种基本数据类型,对象引用。方法执行完后,虚拟机栈就会自动释放该方法栈帧的内存空间

    • 实例变量:堆:它唯一目的就是存放对象实例,几乎所有对象的实例都在这里分配内存。

    • 类变量:方法区:用于存储已被虚拟机加载的类信息,常量,静态常量,即时编译器编译后的代码等数据

  4. 作用域
    • 局部变量:声明处开始,到所属的 } 结束

    • 实例变量:在当前类中 “this ”(有时this. 可以省略),在其他类中 “对象名. ” 访问

    • 类变量:在当前类中 “类名” (有时类名. 可以省略),在其它类中 “类名.” 或 “对象名.” 访问

  5. 生命周期
    • 局部变量:每一个线程,每一次调用执行都是新的生命周期

    • 实例变量:随着对象的创建而初始化,随着对象的被回收而消亡,每一个对象的实例变量都是独立的

    • 类变量:随着类的初始化而初始化,随着类的卸载而消亡,该类的所有对象的类变量是共享的

当局部变量与成员变量重名时,如何区分

  1. 局部变量与实例变量重名
    在实例变量前面加 “this.”进行调用
  2. 局部变量与类变量重名
    在类变量前面加 “类名.”进行调用

SSM 面试题

SpringBean的作用域之间的区别

在Spring的配置文件(beans.xml)中,给 bean加上scope属性来指定bean的作用域如下:

singleton: 唯一 bean 实例,这也是Spring中bean的默认作用域。
prototype: 每次请求都会创建出一个新的bean实例。
request: 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP request 内有效。
session: 同一个HTTP Session共享一个bean,不同的HTTP Session使用不同的bean,该 bean 仅在当前 HTTP session 内有效。以上这两个作用域仅适用于WebApplicationContext环境。
global-session: 全局session作用域,仅仅在基于portlet的web应用中才有意义,Spring5已经没有了。Portlet是能够生成语义代码(例如:HTML)片段的小型Java Web插件。它们基于portlet容器,可以像servlet一样处理HTTP请求。但是,与 servlet 不同,每个 portlet 都有不同的会话。

Spring 支持的常用数据库事务传播行为和事务的隔离级别

事务的隔离级别

TransactionDefinition 接口中定义了五个表示隔离级别的常量:

  • TransactionDefinition.ISOLATION_DEFAULT: 使用后端数据库默认的隔离级别,Mysql 默认采用的 REPEATABLE_READ隔离级别 Oracle 默认采用的 READ_COMMITTED隔离级别.
  • TransactionDefinition.ISOLATION_READ_UNCOMMITTED: 最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读
  • TransactionDefinition.ISOLATION_READ_COMMITTED: 允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生
  • TransactionDefinition.ISOLATION_REPEATABLE_READ: 对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读(原理应该是保存了当前事务开始时的数据库数据值,然后在当前事务中再次读取时都会读取这些保存后的值,而不是从数据库中获取值,因为数据库中的值可能被别的事务修改过了),但幻读仍有可能发生。
  • TransactionDefinition.ISOLATION_SERIALIZABLE: 最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

脏读: 能读取到尚未提交的数据,比如事务A修改了值但是并没有提交而是选择回滚,那么另一个事务在事务A修改之后但没有提交时读取到的数据就是脏数据,因为事务A之后会将修改的数据进行回滚。

不可重复读: 事务A读取到了数据库中的某个值,事务B将这个值修改并提交了,那么事务A再次在本事务中读取这个值时就是修改之后的值,而不是之前读取到的那个值(即不能重复的读取相同的值)。

幻读: 事务A读取了一个表中的部分数据,但是事务B向这个表中插入了新的数据,那么事务A下一次读取时就会读取到这些新的数据(与第一次查出的数据数不一样),像出现了幻觉一样。脏读针对的是具体的某个字段,而幻读针对的是整个表中的数据行

事务的传播行为

支持当前事务的情况:

TransactionDefinition.PROPAGATION_REQUIRED: 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。比如如果a方法被b方法调用了,如果b方法执行时开启了一个事务,那么a方法的执行就在b方法的事务中。等同于b方法中的其他非方法调用代码
TransactionDefinition.PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
TransactionDefinition.PROPAGATION_MANDATORY: 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。(mandatory:强制性)
不支持当前事务的情况:

TransactionDefinition.PROPAGATION_REQUIRES_NEW: 创建一个新的事务,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起。
TransactionDefinition.PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常。
其他情况:

TransactionDefinition.PROPAGATION_NESTED: 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。

Spring MVC 如何解决 POST与GET 请求中文乱码问题

解决 Post 请求中文乱码问题

修改项目中web.xml文件,给其添加一个过滤器即可

<filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
      <param-name>encoding</param-name>
      <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
      <param-name>forceEncoding</param-name>
      <param-value>true</param-value>
    </init-param>
</filter>
  <filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

解决 Get 请求中文乱码问题

修改tomcat中server.xml文件

<Connector URIEncoding="UTF-8" port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />

Spring MVC 的工作流程

image-20221011172249547

流程说明(重要):
1、客户端(浏览器)发送请求,直接请求到 DispatcherServlet。
2、DispatcherServlet 根据请求信息调用 HandlerMapping,解析请求对应的 Handler。
3、解析到对应的 Handler(也就是我们平常说的 Controller 控制器)后,开始由 HandlerAdapter 适配器处理。
4、HandlerAdapter 会根据 Handler 来调用真正的处理器来处理请求,并处理相应的业务逻辑。
5、处理器处理完业务后,会返回一个 ModelAndView 对象,Model 是返回的数据对象,View 是个逻辑上的 View。
6、ViewResolver 会根据逻辑 View 查找实际的 View。
7、DispaterServlet 把返回的 Model 传给 View(视图渲染)。
8、把 View 返回给请求者(浏览器)

Mybatis中当实体类中的属性名和表中的字段不一样时的解决方法

解决方案有三种如下:
1、写 SQL 语句的时候写别名:数据库字段 as 实体类字段,因为as后才是真正查询出来的数据字段名,这时就可以与实体类映射成功了
2、在MyBatis的全局配置文件中开启驼峰命名规则,前提是符合驼峰命名规则

<!-- 开启驼峰命名规则,可以将数据库中下划线映射为驼峰命名
	列如 last_name 可以映射为 lastName
-->
<setting name="mapUnderscoreToCameLCase" value="true" />

3、在Mapper映射文件中使用 resultMap 自定义映射

<!-- 
	自定义映射
-->
<resultMap type="com.atguigu.pojo.Employee" id="myMap">
    <!-- 映射主键 -->
	<id cloumn="id" property="id"/>
    <!-- 映射其他列 -->
    <result column="last_name" property="lastName" />
    <result column="email" property="email" />
    <result column="salary" property="salary" />
    <result column="dept_id" property="deptId" />
</resultMap>

JavaEE面试题

Linux 常用服务类相关命令

常用基本命令 - 进程类,centos 6 和 centos 7 及以上命令有些不同

centos 6

service 服务名 start
service 服务名 stop
service 服务名 restart
service 服务名 reload
service 服务名 status

#查看服务的方法 /etc/init.d/服务名
#通过 chkconfig 命令设置自启动
#查看服务 chkconfig -list | grep 服务名

chkconfig -level 5 服务名 on/off//开关服务的自启动

在这里插入图片描述

Linux 系统有7种服务自启动时的运行级别 (runlevel) : 常用的是级别 3 和 5 。

运行级别0: 系统停机状态,系统默认运行级别不能设为0,否则不能正常启动
运行级别1: 单用户工作状态,root权限,用于系统维护,禁止远程登陆
运行级别2: 多用户状态(没有NFS),不支持网络
运行级别3: 完全的多用户状态(有NFS),登陆后进入控制台命令行模式
运行级别4: 系统未使用,保留
运行级别5: X11控制台,登陆后进入图形GUI模式
运行级别6: 系统正常关闭并重启,默认运行级别不能设为6,否则不能正常启动.

centos 7

systemctl start 服务名(xxx.service)
systemct restart 服务名(xxxx.service)
systemctl stop 服务名(xxxx.service)
systemctl reload 服务名(xxxx.service)
systemctl status 服务名(xxxx.service)

#查看服务的方法 /usr/lib/systemd/system
#查看服务的命令
systemctl list-unit-files
systemctl --type service

#通过systemctl命令设置自启动
自启动 systemctl enable service_name
不自启动 systemctl disable service_name

redis 持久化的类型以及它们的区别

Redis 提供了两种不同形式的持久化的方式。

RDB(Redis DataBase)

  1. 什么是 RDB 呢?
    指定时间间隔然后从内存中的数据集快照中把数据写入磁盘,也就是行话讲的 Snapshot 快照,它的数据恢复是将快照文件读取到内存中。

  2. RDB 备份是如何执行的?
    Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。RDB的缺点是最后一次持久化后的数据可能丢失(因为它是每隔一段时间才会进行持久化操作,如果下次持久化操作还没进行,而redis服务断了,那么从此处到上一次持久化操作中间的数据都会丢失)。

  3. 什么是 fork ?
    在Linux程序中,fork()会产生一个和父进程完全相同的子进程,但子进程在此后多会exec系统调用,出于效率考虑,Linux中引入了“写时复制技术”,一般情况父进程和子进程会共用同一段物理内存,只有进程空间的各段的内容要发生变化时,才会将父进程的内容复制一份给子进程。

  4. RDB 保存的文件
    在 redis.conf 的配置文件中,默认保存文件的名称叫 dump.rdb
    在这里插入图片描述
    ​ rdb文件的保存路径,也可以修改。默认为Redis启动时命令行所在的目录下
    在这里插入图片描述

  5. RDB 保存的策略
    在这里插入图片描述
    ​ 15 分钟 1 次添加 key 的操作,5 分钟 10 次添加 key 的操作,1 分钟 10000 次添加 key 的操作都会触发保存策略。

  6. RDB 的备份
    先通过 config get dir 查询 rdb文件的目录
    将 *.rdb 的文件拷贝到别的地方

  7. RDB 的恢复
    关闭 Redis
    先把备份文件拷贝到拷贝到工作目录下
    启动 Redis,备份数据会直接加载

  8. RDB 的优点

    • 节省磁盘空间
    • 恢复速度快
  9. RDB 的缺点

    • 虽然Redis在fork时使用了写时拷贝技术,但是如果数据庞大时还是比较消耗性能。
    • 在备份周期在一定间隔时间做一次备份, 所以如果Redis意外down掉的话,就会丢失最后一次快照后的所有修改。

AOF(Append Only File)

  1. 什么是 AOF 呢?
    以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,Redis启动之初会读取该文件重新构建数据,换言之,Redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。

  2. AOF 默认不开启,需要手动在配置文件中配置

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t62CrEeO-1665480321115)(C:\Users\Xujx\AppData\Roaming\Typora\typora-user-images\image-20221009120845939.png)]

  3. 可以在redis.conf中配置文件名称,默认为 appendonly.aof

    image-20221009120857550

  4. AOF 和 RDB 同时开启,redis 听谁的
    系统默认取AOF的数据。

  5. AOF 文件故障备份
    AOF的备份机制和性能虽然和RDB不同, 但是备份和恢复的操作同RDB一样,都是拷贝备份文件,需要恢复时再拷贝到Redis工作目录下,启动系统即加载。

  6. AOF 文件故障恢复
    如遇到AOF文件损坏,可通过
    redis-check-aof --fix appendonly.aof 进行恢复

  7. AOF 同步频率设置

  • 始终同步,每次Redis的写入都会立刻记入日志。

  • 每秒同步,每秒记入日志一次,如果宕机,本秒的数据可能丢失。

  • 不主动进行同步,把同步时机交给操作系统。

    image-20221009120920099

  1. Rewrite
    AOF采用文件追加方式,文件会越来越大为避免出现此种情况,新增了重写机制,当AOF文件的大小超过所设定的阈值时,Redis就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集.可以使用命令bgrewriteaof。
  2. Redis如何实现重写?
    AOF文件持续增长而过大时,会fork出一条新进程来将文件重写(也是先写临时文件最后再rename),遍历新进程的内存中数据,每条记录有一条的Set语句。重写aof文件的操作,并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,这点和快照有点类似。
  3. 何时重写?
    重写虽然可以节约大量磁盘空间,减少恢复时间。但是每次重写还是有一定的负担的,因此设定Redis要满足一定条件才会进行重写。
    image-20221009120933003

​ 系统载入时或者上次重写完毕时,Redis会记录此时AOF大小,设为base_size,如果Redis的AOF当前大小>=base_size+base_size*100% (默认)且当前大小>=64mb(默认)的情况下,Redis会对AOF进行重写

  1. AOF 优点

备份机制更稳健,丢失数据概率更低。
可读的日志文本,通过操作AOF稳健,可以处理误操作。

  1. AOF 缺点

比起RDB占用更多的磁盘空间。
恢复备份速度要慢。
每次读写都同步的话,有一定的性能压力。
存在个别Bug,造成恢复不能完全恢复。

MySQL创建索引的条件

索引是帮助数据库高效获取数据的数据结构。可以简单理解为”排好序的快速查找数据结构”。索引一般来说其本身内存很大,不可能全部存在内存中,因此索引往往以索引文件的形式存储在磁盘上。

索引与我们的字典很像,索引可以提高数据检索的效率,但同时会降低更新表的速度,因为我们在更新表时,不仅要更新数据值,而且要同步更新添加了索引列的字段的索引信息。

什么时候适合创建索引

  1. 主键自动建立唯 一 索引
  2. 频繁作为查询条件的字段应该创建索引
  3. 查询中与其它表关联的字段,外键关系建立索引
  4. 频繁更新的字段不适合创建索引,因为每次更新不单是更新了记录还会更新索引
  5. 单键组索引的选择问题,who? 在高并发下领向创建组合索引
  6. 意询中排序的字段,排序字段若通过索引法访问将大大提高排序速度
  7. 查询中统计或者分组字段

什么时候不适合创建索引

  1. 表记录太少
  2. 经常增删改的表
    因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件数据重复且分布平均的表字段,因此应该只为最经常查询和最经常排序的数据列建立索引。
  3. 注意,如果某个数据列包含许多重复的内容,为它建立索引就没有太大的实际效果。因为这样的字段其过滤性不好,并不能通过其值精确定位到某一条数据

JVM 垃圾回收机制

GC(垃圾回收)主要发生在堆区,方法区很少发生垃圾收集。所以堆是垃圾收集器的工作重点

从GC次数上讲:

  1. 频繁收集Young区
  2. 较少收集Old区(Young区和Old区同属于堆区)
  3. 基本不收集Perm区(元空间)

引用计数算法是四大算法中的唯一一个标记阶段的算法且并没有被采纳,JVM中标记阶段的具体实现是用的可达性分析算法。

  1. 复制算法:年轻代中的垃圾收集叫做Minor GC,这种GC算法采用的就是复制算法。年轻代中的Eden区和survivor0区和survivor1区就可以说是对复制算法的具体实现。
  2. 标记清除算法:主要用于老年代,且标记清除算法清除的是未被标记的对象,因为通过可达性分析JVM只能找到所有存活的对象,这种算法因为事先并不知道垃圾对象的内存位置,所以清除之后是会产生内存碎片的。
  3. 标记压缩算法:主要是对内存碎片的整理工作,把所有对象向内存空间的一边进行挪动
  4. 引用计数算法:通过对每一个对象是否有引用来判定这个对象是否是存活的,但是有一个致命的缺点就是其无法解决循环引用问题。

项目面试题

redis 在项目中的使用场景

数据类型使用场景
String比如我想知道什么时候封锁一个IP(某一个IP地址在某一段时间内访问的特别频繁,那有可能这个IP可能存在风险,所以对它进行封锁),使用Incrby命令记录当前IP访问次数 存储用户信息【id,name,age】 存储方式:set(userKey,用户信息字符串)
Hash存储用户信息【id,name,age】
存储方式:Hset(key,filed,value)
hset(userKey,id,101)
hset(userKey,name,“admin”)
hset(userKey,age,23)
这样存储的好处:当修改用户信息某一项属性值时,直接通过filed取值,并修改值
-----修改案例------
hget(userKey,id)
hset(userKey,id,102)
为什么不使用String存储?
获取方式:get(userKey)
会把参数为userKey对应的用户信息字符串全部进行反序列号,而用户信息字符串包含了用户所有的信息
如果我只修改用户的ID,那反序列化的其他信息其实是没有任何意义的
序列化与反序列化是由IO进行操作的,使用String类型存储增加了IO的使用次数,降低了程序的性能
对值为某类信息时不建议使用String类型存储
List实现最新消息的排行,还可以利用List的push命令,将任务存在list集合中,同时使用另一个pop命令将任务从集合中取出 Redis——list数据类型来模拟消息队列。 比如:电商中的秒杀就可以采用这种方式来完成一个秒杀活动
set特殊之处:可以自动排重。 比如微博中将每个人的好友存在集合(Set)中 如果求两个人的共同好友的操作,我们只需要求交集即可。(交/并集命令)
Zset有序集合(sorted set),以某一个条件为权重,进行排序。 比如:京东看商品详情时,都会有一个综合排名,还有可以安装价格、销量进行排名

Elasticsearch 与 solr 的区别

背景:他们都是基于 Lucene 搜索服务器基础上开发,一款优秀的,高性能的企业级搜索服务器,【是因为他们都是基于分词技术构建的倒排索引的方式进行查询】

开发语言: Java

诞生时间:Solr:2004年诞生;ES:2010年诞生

主要区别:

  1. 当实时建立索引的时候,solr 会产生 io 阻塞,而 es 不会,es 查询性能要高于 solr
  2. 在不断动态添加数据的时候,solr 的检索效率会变得低下,而 es 没有什么变化
  3. Solr 利用 zookeeper 进行分布式管理(一个zookeeper可以管理一个solr集群),而 es 自带有分布式系统的管理功能,Solr 一般都要部署到 web 服务器上,比如 tomcat,启动 tomcat 的时候需要配置 tomcat 和 solr 的 关联 【 Solr 的本质,是一个动态的 web项目】
  4. Solr支持更多格式的数据 【xml、json、csv 】等,而 es 仅仅支持 json 文件格式
  5. Solr 是传统搜索应用的有利解决方案,但是 es 更加适用于新兴的是是搜索应用
    单纯的对已有的数据进行检索, solr 效率更好,高于 es
  6. Solr 官网提供的功能更多哦,而 es 本身更加注重于核心功能,高级功能都有第三方插件完成

单点登录

单点登录: 即一处登录多处使用!
前提:单点登录多使用在分布式系统中

Demo:
参观动物园流程
检票员=认证中心模块
1、我直接带着大家进动物园,则会被检票员拦住【看我们是否有票】,没有【售票处买票】
登录=买票
2、我去买票【带着票,带着大家一起准备进入动物园】 检票员check【有票】
Token = piao
3、我们手中有票就可以任意观赏动物园的每处景点
京东:单点登录,是将 token 放入到 cookie 中
案例:将浏览器的 cookie 禁用,则在登录京东则失效,无论如何登录不了

购物车实现过程

在这里插入图片描述

消息队列在项目中的使用

背景: 在分布式系统中如何处理高并发的
由于在高并发的环境下,来不及同步处理用户发送的请求,则会导致请求发生阻塞,比如说,大量的 insert,update 之类的请求同时到达数据库 MySQL, 直接导致无数的行锁表锁,甚至会导致请求堆积过多,从而触发 too many connections ( 链接数太多 ) 错误,使用消息队列可以解决 【异步通信】

  1. 异步

在这里插入图片描述
2. 并行image-20221009170643332
3. 排队
image-20221009170703268
4. 消息队列在电商中的使用场景
image-20221009170719061
5. 消息队列的弊端
消息的不确定性: 延迟队列 和 轮询技术来解决问题即可!


感谢耐心看到这里的同学,觉得文章对您有帮助的话希望同学们不要吝啬您手中的赞,动动您智慧的小手,您的认可就是我创作的动力!
之后还会勤更自己的学习笔记,感兴趣的朋友们点点关注哦。

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值