Java面试题总结

Java面试题总结

文章目录

Java基础

JDK、JRE、JVM的区别

  • JDK:java开发工具包,是java的核⼼,包括:JRE+编译、运行等命令工具
  • JRE:java运行环境,是运行java程序所必须的环境集合,包括:JVM+java系统类库
  • JVM:java虚拟机,是java实现跨平台的最核⼼部分,能够运行java语⾔所开发的程序

java的8种基本数据类型是什么?(简述java的8种基本数据类型)

8种基本数据类型包括:byteshortintlongfloatdoublebooleanchar

  • byte:字节型,用于存储整数的, 占用1个字节,范围-128到127
  • short:短整型,用于存储整数的,占用2个字节,范围-32768到32767
  • int:最常用的整型,用于存储整数的,占用4个字节,范围-231 到 231-1
  • long:长整型,用于存储较大的整数, 占用8个字节,范围-263到 263-1
  • float:单精度符点数,用于存储小数的,占用4个字节,不能表示精确的值
  • double:双精度符点数,最常用的存储小数的类型,占用8个字节,不能表示精确的值
  • boolean:布尔型,用于存储truefalse,占用1个字节
  • char:字符型,采用Unicode字符编码格式,用于存储单个字符,占用2个字节

switch可以作用于哪些数据类型上?

byteshortintcharString,枚举,其余类型都不允许

重写(overriding)与重载(overloading)的区别

  • 重写 :发⽣在⽗子类中,方法名相同,参数列表相同
  • 重载:发⽣在同⼀类中,方法名相同,参数列表不同

实例变量与静态变量的区别

  • 实例变量和静态变量都属于成员变量
  • 实例变量 :是属于对象的,在创建对象时存储在内存堆中,创建多少个对象,则实例变量就会在内存中存在多少份,需要通过引用变量来访问
  • 静态变量 :是属于类的,在类被加载时存储在内存方法区中,无论创建多少个对象,静态变量在内存中都只有⼀份,常常通过类名点来访问

抽象类和接口的区别

  • 抽象类 :
    • 由abstract修饰
    • 可以包含变量、常量、构造方法、普通方法、静态方法、抽象方法
    • 派⽣类通过extends继承
    • 只能继承⼀个(单⼀继承)
    • 抽象类中的成员,任何访问权限都可以(默认为默认权限(同包中))
  • 接口:
    • 由interface定义
    • 可以包含常量、抽象方法、静态方法(1.8后)、默认方法(1.8后)
    • 实现类通过implements实现
    • 可以实现多个(体现多实现)
    • 接口中的成员,访问权限只能是public(默认public权限)

java是值传递还是引用传递?

  • 在java中,无论是基本类型还是引用类型,都是值传递
    • 对于基本类型而⾔,传递的是具体的值的副本
    • 对于引用类型而⾔,传递的是具体的地址的副本

集合

ArrayList和LinedList的区别

  • 数据结构实现:ArrayList :基于数组,容量不够时候采用复制方式扩容。LinkedList:使用链表实现。
  • 随机访问效率:ArrayListLinkedList在随机访问的时候效率要高,因为 LinkedList 是链表结构,需要依次查找元素,性能不高。
  • 增加和删除效率 :LinkedList ⾸位操作具备很高效率。ArrayList 的头部性能稍差。
  • 线程安全:ArrayListLinkList 都是不同步的,不保证线程安全。
  • 综合来说,需要频繁读取集合中的元素时,更推荐使用 Arrayist;而在头尾增删操作较多时,更推荐使用 LinkedListArrayList综合性能优秀,优选之!

手写一下HashMap的几种遍历方式

  • Entry 遍历
  • keySet 遍历
  • foreach 遍历
  • keySet foreach 遍历

Collection和Collections的区别

  • Collection是一个集合接口,集合类的一个顶级接口。它定义了集合通用方法。
  • Collection接口直接继承的有ListSet
  • Collections则是集合类的一个工具类,其中提供了一系列静态方法,用于对集合中元素进行排序、搜索以及线程安全等各种操作。

Map、List和Set的区别是什么?

  • List 线性表,有序可以重复的集合,元素有先后次序,可以按照位置访问元素,可以存储null
  • Set元素不重复集合,重复元素算⼀个,不保证元素的先后次序,可以存储⼀个null
  • Map 元素按照key:value成对存储,可以按照key查找value,查找性能好,key不可以重复,可以存储⼀个null key

序列化

什么叫对象序列化,什么是反序列化,实现对象序列化需要做哪些工作

  • 序列化:把对象转化为可传输的字节序列过程称为序列化
  • 反序列化:把字节序列还原为对象的过程称为反序列化
  • 其实序列化最终的⽬的是为了对象数据存储,或者进行⽹络传输
  • java 实现序列化很简单,只需要被序列化对象类实现Serializable 接口 ,然后使用对象流进行序列化和反序列化。
  • 使用ObjectOutputStream 进行对象序列化
  • 使用ObjectInputStream 进行对象反序列化

线程

创建线程的几种方式是什么?

  • 通过继承Thread类创建线程类
  • 实现Runnable接口创建线程类
  • 通过CallableFuture接口创建线程

进程和线程的区别

进程是资源分配的最小单位,线程是CPU调度的最小单位。操作系统执行程序时候,按照进程分配内存等资源,而执行程序时候以线程为单位执行程序中的指令。⼀个进程内部包含多个并发执行的线程。在进程内部多个线程共享⼀个进程的内存资源。

什么是死锁,产⽣死锁的四个条件

  • 互斥条件:⼀个资源每次只能被⼀个进程使用 。
  • 请求与保持条件:⼀个进程因请求资源而阻塞时,对已获得的资源保持不放。
  • 不剥夺条件 :进程已获得的资源,在末使用完之前,不能强行剥夺。
  • 循环等待条件 :若干进程之间形成⼀种头尾相接的循环等待资源关系。

这四个条件是死锁的必要条件,只要系统发⽣死锁,这些条件必然成⽴,而只要上述条件之⼀不 满⾜,就不会发⽣死锁。

线程池有几种?

Java通过Executors(JUC)提供四种线程池,分别为:

  • newCachedThreadPool创建⼀个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
  • newFixedThreadPool创建⼀个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
  • newScheduledThreadPool创建⼀个定长线程池,⽀持定时及周期性任务执行。
  • newSingleThreadExecutor创建⼀个单线程化的线程池,它只会用唯⼀的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

计算机网络

TCP/UDP的区别

  • TCP 基于连接,UDP 基于无连接。
  • TCP 要求系统资源较多,UDP 较少。
  • UDP 程序结构较简单。
  • TCP 保证数据正确性,UDP 可能丢包。
  • TCP 保证数据顺序,UDP 不保证。

三次握手四次挥手

三次握手的原文是three-way handshake,整个名词的可以翻译为:需要三个步骤才能建立握手/连接的机制。当然,三次握手也可以叫three-message handshake,通过三条消息来建立的握手/连接。

  • 第⼀次握手:客户端什么都不能确认;服务器确认了对方发送正常, ⾃己接收正常
  • 第⼆次握手:
    • 客户端确认了: ⾃己发送、接收正常,对方发送、接收正常;
    • 服务器确认了:对方发送正常, ⾃己接收正常
  • 第三次握手(客户端发送 ACK 报文给服务器):
    • 客户端确认了: ⾃己发送、接收正常,对方发送、接收正常;
    • 服务器确认了: ⾃己发送、接收正常,对方发送、接收正常
  • TCP: 连接的释放需要发送四个包(执行四个步骤),因此称为四次挥手(Four-way-handshake),客户端或服务端均可主动发起挥⼿动作
  • 通俗的来说,两次挥手就可以释放⼀端到另⼀端的 TCP 连接,完全释放连接⼀共需要四次挥手。

HTTP请求结构?HTTP请求头中有什么?

  • ⼀个HTTP请求报文由四个部分组成:请求行、请求头部、空行、请求数据

  • 请求头

    1.Accept:浏览器可接受的mime类型。

    2.Accept-Charset:浏览器可接受的字符集。

    3.Accept-Encoding:浏览器能够进行解码的方式。

    4.Content-Length:表示请求消息的长度。

    5.Host: 客户端告诉服务器,想访问的主机名。

    6.Cookie:客户端可以向服务器带数据,只是非常重要的信息之⼀。

GET和POST的区别

  • GET方式是通过请求行传递用户所输入的内容,其内容会全部显示的浏览器的地址栏中;
  • GET提交具有长度限制
  • GET是从服务器上获取数据
  • GET请求没有HTTP消息体
  • POST提交将用户所输入数据放到HTTP消息体中发送到服务器端
  • POST没有提交长度限制
  • POST是向服务器传送数据

介绍⼀下404状态码是什么意思以及解决方案?

  • 404状态码,代表找不到资源

  • 需要先判断请求的是静态资源文件还是动态:

    • 如果是静态资源文件:

      检查请求路径是否正确, 检查static文件夹下的文件名是否正确,文件的位置是否正确, 如果以上都没问题则ReBuild工程,然后重启工程

    • 如果请求的是动态资源:

      检查请求路径是否正确,检查controller的包是否在⾃带的包下面, 检查Controller类里面是否添加了@Controller注解, 检查@RequestMapping注解里面的路径是否正确, 如果以上全部正确 则Rebuild工程,然后重启工程

介绍⼀下500状态码是什么意思以及解决方案?

  • 500状态码, 代表服务器业务代码过程中出错
  • 此时检查idea里面提示的错误信息

异常

Java异常体系

  • 顶层是throwable然后是errorexception
  • Error就是虚拟机错误,比如典型的outofMemoryError stackOverFlowError,出现以后系统基本崩溃,不可恢复;
  • RuntimeException,也称为非检查异常:程序运行过程中才可能发⽣的异常。⼀般为代码的逻辑错误。例如:类型错误转换,数组下标访问越界,空指针异常、找不到指定类等等。
  • 检查异常:编译期间可以检查到的异常,必须显式的进行处理(捕获或者抛出到上⼀ 层)。例如:IOExceptionFileNotFoundException等等。

反射

如何用反射获取方法?

  1. ⾸先找到类型的Class对象

    • Class.forName(类型)
    • 类型.class
    • 对象.getClass()
  2. 然后在类型上查找方法

    getMethods();//获取包括⾃身和继承(实现)过来的所有的public方法
    
    getDeclaredMethods();//获取⾃身所有的方法
    
    getMethod(方法签名);//表示获取指定的⼀个公共的方法,包括继承的
    
    getDeclaredMethod(方法签名);//表示获取本类中的⼀个指定的方法,不包括继承的方法
    
    //方法签名包括:方法的名字,参数的Class类型列表
    

什么是反射

  • Java反射(Java Reflection)是指在运行时获取程序的类型信息并可以操作对象的机制。通过反射,可以在运行时获取类的成员变量、方法、构造函数等信息,并可以在运行时调用对象的方法,创建对象的实例,操作对象的属性等。
  • 在Java中,反射机制主要通过以下几个类实现:
    • Class类:表示类的类型,通过该类可以获取类的构造函数、成员变量、方法等信息。
    • Constructor类:表示类的构造函数类型,通过该类可以创建类的实例。
    • Field类:表示类的成员变量类型,通过该类可以获取、设置类的成员变量的值。
    • Method类:表示类的方法类型,通过该类可以调用类的方法。
  • 反射机制在Java中具有⼴泛的应用,例如:
    • 动态代理:可以通过反射⽣成实现了某个接口的代理类,实现动态代理。
    • 依赖注入:可以通过反射获取类的构造函数、成员变量等信息,实现依赖注入。
    • 注解处理器:可以通过反射获取类的注解信息,实现注解处理器。
    • 配置文件解析器:可以通过反射获取类的属性信息,实现配置文件解析器。
  • 尽管反射机制可以方便地获取类的信息并进行操作,但是它也具有⼀定的缺点,如性能较差、代码可读性差、安全性差等。因此,在实际开发中,应该根据实际情况谨慎使用反射机制。

数据库

SQL语句分类以及作用

  • DDL:数据定义语⾔, 包括数据库相关和表相关的SQL语句
  • DML:数据操作语⾔, 包括数据的增删改查 , 查询也属于数据查询语⾔
  • DQL:数据查询语⾔, 只包括select相关
  • TCL:事务控制语⾔, 包含和事务相关的SQL
  • DCL: 数据控制语⾔, 包含用户管理,以及权限管理相关SQL

基础增删改查的格式

  1. 插入数据

    • 全表插入:

      insert into 表名 values(1,值2,值3);
      
    • 指定字段插入:

      insert into 表名(字段1名,字段2) values(1,值2);
      
    • 批量插入:

      insert into 表名(字段1名,字段2) values(1,值2)(1,值2);
      
  2. 删除数据:

    delete from 表名 where 条件
    
  3. 修改数据:

     update 表名 set 字段名=值,字段名=where 条件
    
  4. 查询数据:

     select 字段信息 from 表名 where 条件
    

模糊查询和去重

  • 在需要去重的字段前面加上distinct
  • %代表0或多个未知字符
  • _代表1个未知字符
  • 举例:第三个字符是x 倒数第⼆个是y:_ _x%y_

数据库设计中包含哪些关联关系

  • 创建表时,表和表之间存在的业务关系成为关联关系
    • ⼀对⼀:有AB两张表,A表中的⼀条数据对应B表中的⼀条数据,同时B表中的⼀条数据也是对应A表中的⼀条数据 , 在任何⼀张表中添加建立关系的字段指向另外⼀个表的主键
    • ⼀对多:有AB两张表,A表中的⼀条数据对应B表中的多条数据,同时B表中的⼀条数据对应A表中的⼀条数据。在多的表中添加建立关系的字段指向另外⼀个表的主键
    • 多对多:有AB两张表,A表中的⼀条数据对应B表中的多条数据,同时B表中的⼀条数据也对应A表中的多条数据。创建⼀个单独的关系表,表里面至少有两个字段指向另外两张表的主键

数据库中常见的聚合函数?

在关系型数据库中,聚合函数(Aggregate Functions)是用于计算数据集合中的统计值的函数。常见的聚合函数包括以下几个:

  • COUNT:计算数据集合中的记录数。
  • SUM:计算数据集合中某个字段的总和。
  • AVG:计算数据集合中某个字段的平均值。
  • MAX:获取数据集合中某个字段的最大值。
  • MIN:获取数据集合中某个字段的最小值。

这些聚合函数可以与 SQL 语句的 SELECT 语句结合使用,对数据集合进行统计和汇总。

关联查询有几种?列举常见的关联查询。

同时查询存在关联关系的多张表的查询方式称为关联查询

  • 等值连接:

    select * from A,B where 关联关系 and 其它条件
    
  • 内连接:inner joinjoin,两者效果相同

    select * from A join B on 关联关系 where 其它条件
    
  • 左外连接 / 右外连接:left join / right join

    select * from A left / right join B on 关联关系 where 其它条件外连接:
    
  • 全连接:mysql不⽀持 full join,使用union替代

  • ⾃连接

等值连接 / 内连接和外连接的应用场景

  • 如果查询的是两张表的交集数据则可以使用等值连接或内连接(推荐)
  • 如果查询的是⼀张表的全部以及另外⼀张表的交集数据则使用外连接

分页和排序

  • 分页:limit跳过条数,请求条数
    • 如:查询第5页的8条数据: limit 32,8
  • 排序:order by字段名asc升序(默认)或desc降序
    • 多字段排序:order by 字段名 升序或降序,字段名 升序或降序;

mysql查询出来的结果分页展示⼀般怎么做?

  • 方式1:

    select * from table order by id limit m, n;
    

    该语句的意思就是查询m+n条记录,去掉前m条,返回后n条。⽆疑该查询能够实现分页,但m越大,查询性能就越低,因为MySQL需要扫描全部m+n条记录。

  • 方式2:

    select * from table where id > max_id order by id limit n;
    

    该查询同样会返回后n条记录,却⽆需像方式1扫描前m条记录,但必须在每次查询时拿到上⼀次查询(上⼀页)的最大id(或最小id),是比较常用的方式。当然该查询的问题也在于我们不⼀定能拿到这个id,比如当前在第3页,需要查询第5页的数据,就不行了。

  • 方式3:

    为了避免方式2不能实现的跨页查询,就需要结合方式1。性能需要,m得尽量小。比如当前在第3页,需要查询第5页,每页10条数据,且当前第3页的最大id为max_id,则:

    select * from table where id > max_id order by id limit 1010;
    

    该方式就部分解决了方式2的问题,但如果当前在第2页,要查第1000页,性能仍然较差。

  • 方式4:

    select * from table as a inner join (select id from table order by id limit m,n) as b on a.id = b.id order by a.id;
    

    该查询同方式1⼀样,m的值可能很大,但由于内部的子查询只扫描了id字段,而非全表,所以性能要强于方式1,并且能够解决跨页查询问题。

  • 方式5:

    select * from table where id > (select id from table order by id limit m, 1) limit n;
    

    该查询同样是通过子查询扫描字段id,效果同方式4。但方式5的性能会略好于方式4,因为它不需要进行表的关联,而是⼀个简单的比较,在不知道上⼀页最大id的情况下,是比较推荐的用法。

分组和having

  • 分组查询可以将某个字段相同值的数据划分为⼀组然后进行统计查询
    • 格式:group by 分组字段名
  • having: 和分组查询结合使用,在having后面写聚合函数条件,where后面写普通字段条件

什么是事务,以及事务的应用,举例说明

  • 事务:指构成单个逻辑工作单元的操作集合
  • 事务是指是程序中⼀系列严密的逻辑操作,而且所有操作必须全部成功完成,否则在每个操作中所作的所有更改都会被撤消。可以通俗理解为:就是把多件事情当做⼀件事情来处理,好比大家同在⼀条船上,要活⼀起活,要完⼀起完

ACID指的是什么

  • 原子性(Atomicity):操作这些指令时,要么全部执行成功,要么全部不执行。只要其中⼀个指令执行失败,所有的指令都执行失败,数据进行回滚,回到执行指令前的数据状态。
  • ⼀致性(Consistency):事务的执行使数据从⼀个状态转换为另⼀个状态,但是对于整个数据的完整性保持稳定。
  • 隔离性(Isolation):隔离性是当多个用户并发访问数据库时,比如操作同⼀张表时,数据库为每⼀个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。即要达到这么⼀种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。
  • 持久性(Durability):当事务正确完成后,它对于数据的改变是永久性的。

对SQL的优化方式有哪些

  • 减少数据访问: 设置合理的字段类型,启用压缩,通过索引访问等减少磁盘IO
  • 返回更少的数据: 只返回需要的字段和数据分页处理 减少磁盘IO及⽹络IO
  • 减少交互次数: 批量DML操作,函数存储等减少数据连接次数
  • 减少服务器CPU开销: 尽量减少数据库排序操作以及全表查询,减少CPU内存占用
  • 利用更多资源: 使用表分区,可以增加并行操作,更大限度利用CPU资源

总结到SQL优化中,就三点:

  1. 最大化利用索引;
  2. 尽可能避免全表扫描;
  3. 减少⽆效数据的查询;

对SQL的优化流程

  • 分析语句,是否加载了不必要的字段/数据。
  • 分析 SQL 执行计划(explain extended),思考可能的优化点,是否命中索引等。
  • 查看 SQL 涉及的表结构和索引信息。
  • 如果 SQL 很复杂,优化 SQL 结构。
  • 按照可能的优化点执行表结构变更、增加索引、SQL 改写等操作。
  • 查看优化后的执行时间和执行计划。
  • 如果表数据量太大,考虑分表。
  • 利用缓存,减少查询次数。

创建索引的条件是什么

  • 字段的数值有唯⼀性的限制
    • 业务上具有唯⼀特性的字段,即使是组合字段,也必须建成唯⼀索引。
    • 说明:不要以为唯⼀索引影响了 insert 速度,这个速度损耗可以忽略,但提高查找速度是明显的。
  • 频繁作为WHERE查询条件的字段
  • 经常GROUP BYORDER BY的列
    • 索引就是让数据按照某种顺序进行存储或检索,因此当我们使用 GROUP BY对数据进行分组查询,或者使用ORDER BY对数据进行排序的时候,就需要对分组或者排序的字段进行索引 。如果待排序的列有多个,那么可以在这些列上建立组合索引 。
  • UPDATEDELETEWHERE条件列
    • 对数据按照某个条件进行查询后再进行UPDATEDELETE的操作,如果对WHERE字段创建了索引,就能大幅提升效率。原理是因为我们需要先根据WHERE条件列检索出来这条记录,然后再对它进行更新或删除。如果进行更新的时候,更新的字段是非索引字段,提升的效率会更明显,这是因为非索引字段更新不需要对索引进行维护。
  • DISTINCT字段需要创建索引
  • 多表JOIN连接操作时,创建索引
  • 使用列的类型小的创建索引
  • 使用字符串前缀创建索引
  • 区分度高(散列性高)的列适合作为索引
  • 使用最频繁的列放到联合索引的左侧
  • 在多个字段都要创建索引的情况下,联合索引优于单值索引

事务的隔离级别

为了达到事务的四大特性(ACID),数据库定义了 4 种不同的事务隔离级别:

  • READ-UNCOMMITTED(读取未提交):最低的隔离级别,允许脏读,也就是可能读取到其他会话中未提交事务修改的数据,可能会导致脏读、幻读或不可重复读。
  • READ-COMMITTED(读取已提交): 只能读取到已经提交的数据。Oracle 等多数数据库默认都是该级别 (不重复读),可以阻止脏读,但是幻读或不可重复读仍有可能发⽣。
  • REPEATABLE-READ(可重复读):对同⼀字段的多次读取结果都是⼀致的,除非数据是被本身事务⾃己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发⽣。
  • SERIALIZABLE(可串行化):最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产⽣干扰,也就是说,该级别可以防止脏 读、不可重复读以及幻读。
  • MySQL 默认采用的REPEATABLE_READ隔离级别。

可重复读解决了哪些问题?

  • 可重复读的核⼼就是⼀致性读(consistent read);保证多次读取同⼀个数据时,其值都和事务开始时候的内容是⼀致,禁止读取到别的事务未提交的数据,会造成幻读。
  • 而事务更新数据的时候,只能用当前读。如果当前的记录的行锁被其他事务占用的话,就需要进入锁等待。
  • 查询只承认在事务启动前就已经提交完成的数据。
  • 可重复读解决的是重复读的问题,可重复读在快照读的情况下是不会有幻读,但当前读的时候会有幻读。

JDBC执行SQL语句有哪些步骤?

//1.获取数据库链接对象 异常抛出
Connection conn = DriverManager.getConnection( "jdbc:mysql://localhost:3306/empdb?characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false","root","root");
System.out.println("链接对象:"+conn);
//2.创建执行SQL语句的对象
Statement s = conn.createStatement();
//3.执行SQL语句
s.execute("create table jdbct1(id int)");
//4.关闭资源
conn.close();

Statement的相关方法有哪些?

  • execute(sql)执行任意SQL语句,推荐执行DDL(数据操作语⾔)
  • executeUpdate(sql)执行增删改相关SQL
  • ResultSet rs = executeQuery(sql)执行查询相关SQL语句

讲⼀下如何遍历ResultSet结果集对象中的数据

通过while循环遍历结果集中的对象,在while后面的括号中调用结果集对象的next()方法,此方法是询问是否有下⼀条数据,并且让游标往下移动, 在方法中调用getInt/String/Double....方法获取当前游标指向的这行数据

//遍历结果集对象 rs.next()询问是否有下⼀条数据有返回true否则返回false 同时游标往下移动
while(rs.next()){
    String name = rs.getString("name");
    double sal = rs.getDouble("sal");
    System.out.println(name+":"+sal);
}

什么是SQL注入以及如何解决?

  • 用户往传递值的地方传递进去了SQL语句导致原有SQL语句的逻辑发⽣改变,这个过程称为SQL注入
  • 通过PreparedStatement对象解决SQL注入问题
    • 因为PreparedStatement对象的预编译效果是创建PreparedStatement对象时,对SQL语句进行编译,此时会对SQL语句的语法格式进行校验,并且对SQL语句的语义部分进行锁死, 之后用户输入的内容不管内容是什么都以值的形式添加到SQL语句当中, 这样就不会影响原有SQL语句的语义部分,从⽽避免了SQL注入的问题

前端

分区标签的作用以及有哪些分区标签

作用:可以理解为容器,将多个有相关性的标签添加到⼀个分区标签里面便于统⼀管理

  • div块级分区元素独占⼀行
  • span行内分区元素共占⼀行
  • HTML5中新增的分区标签,作用是和div⼀样,为了提高代码的可读性
    • header
    • footer
    • main
    • nav
    • section

form表单中的控件有哪些?

  • 文本框:<input type='text' name='username' value='设置默认值' placeholder="占位文本" readonly maxlength='5'>
  • 密码框:<input type='passwod' 属性和文本框作用⼀样>
  • 单选:<input type="radio" name value checked>
  • 多选:<input type="checkbox" 属性和单选作用⼀样>
  • ⽇期: <input type="date">
  • 文件: <input type="file">
  • 下拉选:<select name><option>xxxxx</option></select>
  • 提交按钮:<input type='submit'>
  • 重置按钮:<input type='reset'>
  • ⾃定义按钮:<input type='button'>

相对定位和绝对定位的区别

  • 相对定位:元素不脱离文档流(占着原来的位置), 通过left/right/top/bottom让元素相对于初始位置做偏移
  • 绝对定位:元素脱离文档流(不占原来的位置) , 通过left/right/top/bottom让元素相对于窗口(默认)或某⼀个上级元素做偏移(需要在上级元素中设置相对定位)

说说你对浮动定位的理解

  • 格式:float:left/right
  • 元素脱离文档流,元素从当前所在行向左或向右浮动, 当撞到上级元素边缘或其它浮动元素时停止移动
  • 多个浮动元素⼀行装不下时会⾃动折行,折行时 如果有凸出的元素会卡住
  • 当某个元素的所有⼦元素全部浮动时,⾃动识别的高度会为0,后面的元素会顶上来导致显示异常,通过给元素添加overflow:hidden解决
  • 应用场景: 当需要将纵向排列的元素改成横向排列时使用浮动定位

盒⼦模型包含哪些样式? 作用是什么? 包括content和boder边框相关的内容

  • 盒⼦模型= content内容+margin外边距+border边框+padding内边距
  • 盒⼦模型相关样式控制元素的显示效果content控制元素的显示尺寸, margin控制元素的显示位置, border边框控制边框效果, padding控制元素内容的位置
    • conent包含:widthheight行内元素不能修改宽高
    • border边框 :赋值方式: border:粗细 样式 颜⾊;
      • 圆角 border-radius:20px;值越⼤越圆

讲⼀下什么是外边距,什么是内边距

  • margin外边距: 元素距离上级元素或相邻兄弟元素的距离称为外边距, 行内元素上下外边距⽆效, 粘连问题:当元素的上边缘和上级元素的上边缘重叠时给元素添加上外边距会出现粘连问题 给元素添加overflow:hidden解决
  • padding内边距: 元素边缘距内容的距离称为内边距,给元素添加内边距会影响元素的显示宽高

元素显示方式包含哪几种

通过以下四种样式的值控制元素的显示方式:

  • block: 块级元素的默认值
    • 特点: 独占⼀行,可以修改元素宽高, 包括:h1-h6 ,p,div
  • inline: 行内元素的默认值
    • 特点: 共占⼀行, 不能修改元素宽高, 包括:span,b,i,s,u,a
  • inline-block: 行内块元素的默认值
    • 特点: 共占⼀行,可以修改元素宽高, 包括:input ,img
  • none: 隐藏元素

CSS三⼤特性

  • 继承性:元素可以继承上级元素文本和字体相关的样式,部分标签⾃带效果不受继承影响
  • 层叠性: 元素不同的样式可以层叠,多个选择器可能选择到同⼀个元素,如果作用的样式不同则全部层叠⽣效,如果作用的样式相同则由优先级来决定
  • 优先级:指选择器的优先级, 作用范围越小优先级会越高,id>class>标签名>继承(属于间接选中), 加上!important关键字的样式优先级最高

window对象中常用的方法有哪些?

  • isNaN(变量)判断变量是否是NaN, NaN是Not a Number的缩写,代表不是⼀个数
  • alert("xxx") :弹出提示框
  • confirm("xxx"):弹出确认框
  • prompt("xxx"):弹出文本框
  • parseFloat()parseInt():将字符串转成整数或小数
  • let timer = setInterval(方法,时间间隔):开启定时器
  • clearInterval(timer); :停止定时器
  • setTimeout(方法,时间间隔):开启只执行⼀次的定时器

前端MVC设计模式

  • MVC设计模式, 将实现⼀个前端业务的所有代码划分为三部分,包括以下三部分:
    • M:Model模型, ⼀般指数据模型相关代码
    • V:View视图, 指页面标签相关代码
    • C:Controller控制器, 指将数据展示到页面中的过程代码
  • MVC设计模式中Controller里面将数据展示到页面的过程中需要频繁的进行DOM相关操作,频繁的DOM操作影响执行效率,MVVM设计模式可以解决此问题

前端MVVM设计模式

  • MVVM设计模式,将实现⼀个前端业务的所有代码划分为三部分,包括以下三部分:
    • M:Model模型, ⼀般指数据模型相关代码
    • V:View视图, 指页面标签相关代码
    • VM:视图模型, 负责将页面中可能发⽣改变的元素和某个变量进行绑定,并且会⼀直监听这变量值的改变, 当变量的值发⽣改变时,会从内存中找到变量对应的元素,将元素的内容进行改动, 这样的话就避免了每次进行DOM操作遍历查找元素,从⽽提高执行效率

VUE相关指令

  • {{变量}}:插值,将此处显示的文本内容和变量进行绑定,这种写法不依赖标签
  • v-text="变量":让元素的文本内容和变量进行绑定
  • v-html="变量":让元素的标签内容和变量进行绑定
  • v-model="变量":双向绑定(变量的值会影响页面控件显示的内容,控件内容的改变也会影响变量)
  • v-bind:属性名=“值”: 属性绑定,让元素某个属性的值和变量进行绑定去掉v-bind是简写
  • v-on:事件名=“方法” 事件绑定,当事件触发时会调用指定的方法 @事件名是简写
  • v-for="变量 in 数组":循环遍历,遍历的同时⽣成元素
  • v-if="变量":控制元素是否显示,true显示false不显示(删除元素)
  • v-show="变量":控制元素是否显示true显示false不显示(隐藏元素)

Spring框架

Spring两大核心技术是什么?IOC和AOP是什么?简单描述下你对AOP和IOC的理解?

  • Spring两大核心技术分别是IoCAOP
  • IoC控制反转,指的是将对象的管理控制权交给容器。例如由Spring框架来创建、管理对象。
    • 依赖注入DI,指的是为对象的属性或方法的参数注入值。例如Controller中依赖了Service,依赖注入就表现为Controller中的Service注入值。
  • AOP指的是面向切面编程,用于统一管理程序的横向关注点。常见的场景:安全、日志、事务等。例如,基于Spring JDBC的事务管理,还有Spring Security中通过@PreAuthority实现的授权访问,本质上都是通过AOP实现的。

依赖注入的三种方式?

  1. 属性注入
  2. Setter注解
  3. 构造方法注入

AOP是如何实现的?能解决哪些问题?

  • AOP是通过动态代理实现的
  • AOP指的是面向切面编程,用于统一管理程序的横向关注点。常见的场景:安全、日志、事务等。例如,基于Spring JDBC的事务管理,还有Spring Security中通过@PreAuthority实现的授权访问,本质上都是通过AOP实现的。

简述Spring AOP中常用的几种Advice注解

  • @Before(execution):在方法执行前
  • @AfterReturning(execution):在方法正常return
  • @AfterThrowing(execution):在方法抛出异常后
  • @After(execution):在方法结束后,无论正常结束还是异常结束
  • @Around(execution):环绕,唯一可以使ProceedingJoinPoint参数来控制流程的Advice,由于是自行通过调用参数对象来执行连接点方法,所以,可以实现其它所有Advice的效果

Spring Bean的作用域?

  • Spring Bean常见作用域有:singletonprototyperequestsessionglobal session
  • singleton是默认的作用域,是“单例的”,prototype表示“原型”,是“非单例的”,其它作用域仅在Web环境下有效,而且,并不常见,在开发实践中,绝大部分Spring Bean的作用域都是默认的

@Autowired和@Resource注解的区别?

  • @Autowired
    • Spring框架,会先查询匹配类型的对象的数量
      • 如果数量为1,则直接装配,且装配成功
      • 如果数量为0,则取决于@Autowiredrequired属性
        • 属性值为true时,装配失败,在加载SpringApplicationContext时就会报错
        • 属性值为false时,放弃装配,这种情况下可能导致NPE问题
      • 如果数量超过1个,则尝试根据名称来匹配
        • 如果存在名称匹配的Bean,则装配成功
        • 如果不存在名称匹配的Bean,则装配失败,在加载SpringApplicationContext时就会报错。
    • @Autowired可添加在属性上、Setter方法上,还可以添加在构造方法上。
  • @Resource
    • 是Java的注解,位于javax.annotation包下,Spring支持此注解,它首选按byName自动装配,如果匹配失败,再按照类型byType匹配注入
    • @Resource可以添加在属性上、Setter方法上,用于实现自动装配

注意:

在解决同类型对象有多个时,@Autowired可以配合@Qualifier一起使用,通过@Qualifier配置所需要装配的Bean的名称,并且,@Qualifier既可以添加在属性上,还可以添加在方法的参数上,使得@Autowired的使用更加灵活。

另外,在使用IntelliJ IDEA时,有时使用@Autowired时会报错,但实际运行是没有问题的,而改为@Resource却不会报错,这并不表示它建议使用@Resource取代@Autowired,只是它不对@Resource的执行效果进行检查而已。

概述Maven的作用,以及使用注意事项

  • 作用:maven是⼀个项⽬构建和管理的工具,可以通过在pom.xml文件中添加依赖坐标的方式引入三方框架,会⾃动引入其它依赖文件,可以让程序员更加高效便捷的构建工程
  • 使用注意事项
    • 使用idea默认的maven
    • 下载settings.xml配置文件 ,并且把文件放在.m2文件夹下
    • pom.xml进行改动后,需要刷新maven
    • 如果刷新maven报错,可以通过删除.m2文件夹下的repository文件夹进行解决,(因为maven下载依赖数据时有可能丢失数据)删除此文件夹可以将下载的所有数据全部删除,再次刷新maven时会重新下载所有数据

Spring如何解决循环依赖问题?

Spring通过三级缓存解决了循环依赖问题。三级缓存包括singletonObjectsearlySingletonObjectssingletonFactories

  1. 在Spring容器启动过程中,当创建一个Bean时,Spring首先将其放入singletonFactories中,并标记为正在创建,然后继续递归创建该Bean依赖的其他 Bean
  2. 当递归创建到依赖另一个正在创建的Bean时,Spring会从singletonFactories获取正在创建的Bean的代理对象,并返回给依赖它的Bean
  3. 当依赖的Bean创建完成后,Spring会将其放入earlySingletonObjects中,并从singletonFactories中移除,接着,Spring会注入依赖该Bean的其他Bean完成依赖注入
  4. 最后,当所有Bean创建完成后,Spring会将这些Bean放入singletonObjects中,以供其他Bean使用。

通过三级缓存,Spring实现了循环依赖的自动解决。但是,由于Spring采用了代理对象解决循环依赖,因此如果循环依赖的Bean的方法内部需要调用自己,会出现代理对象无法调用到实际对象的情况,需要额外注意。

事务注解以及作用?

  • 基于Spring JDBC的事务管理中,是声明式的事务管理,通过@Transactional注解进行标记。
    • 如果将@Transactional添加在接口上,则此接口的实现类中所有重写的方法都是事务性的
    • 如果添加在接口中的抽象方法上,则实现类中重写的此方法是事务性
    • 如果添加在实现类或实现类中重写的方法,需要注意的是:此注解对于实现类中扩展的方法是无效的。
  • 当方法被标记为事务性的,则具有事务的特征,即符ACID特性,具体表现为一系列的写操作要么全部成功,要么全部失败。
  • 这种事务管理机制,默认为基于RuntimeException进行回滚。
  • 所以,在开发实践中,只要某个业务中涉及超过1次的增、删、改操作,就必须使得这个业务是事务性的,并且,在执行每个增、删、改操作后,应该判断返回的结果,如果不符合预期,必须抛出RuntimeException或其子孙类异常,以保证失败时能够回滚。

Spring常用注解有哪些?都有什么用?

  • @ComponentScan:添加在配置类上,开启组件扫描。如果没有配置包名,则扫描当前配置类所在的包,如果配置了包名,则扫描所配置的包及其子孙包
  • @Component:添加在类上,标记当前类是组件类,可以通过参数配置Spring Bean名称
  • @Controller:添加在类上,标记当前类是控制器组件类,用法同@Component
  • @Service:添加在类上,标记当前类是业务逻辑组件类,用法同@Component
  • @Repository:添加在类上,标记当前类是数据访问组件类,用法同@Component
  • @Configuration:添加在类上,仅添加此注解的类才被视为配置类,通常不配置注解参数
  • @Bean:添加在方法上,标记此方法将返回某个类型的对象,且Spring会自动调用此方法,并将对象保存在Spring容器中
  • @Autowired:添加在属性上,使得Spring自动装配此属性的值,添加在构造方法上,使得Spring自动调用此构造方法,添加在Setter方法上,使得Spring自动调用此方法
  • @Qualifier:添加在属性上,或添加在方法的参数上,配合自动装配机制,用于指定需要装配的Spring Bean的名称
  • @Scope:添加在组件类上,或添加在已经添加了@Bean注解的方法上,用于指定作用域,注解参数为singleton(默认)时为“单例”,注解参数为prototype时为“非单例”
  • @Lazy:添加在组件类上,或添加在已经添加了@Bean注解的方法上,用于指定作用域,当Spring Bean是单例时,注解参数为true(默认)时为“懒加载”,注解参数为false时为“预加载”
  • @Value:添加在属性上,或添加在被Spring调用的方法的参数上,用于读取Environment中的属性值,为对象的属性或方法的参数注入值
  • @Resource:此注解是javax包中的注解,添加在属性上,使得Spring自动装配此属性的值

SpringMVC框架

Spring MVC的处理流程?

  1. 客户端发送请求至前端控制器DispatcherServlet
  2. DispatcherServlet收到请求后,调用处理器映射器HandlerMapping
  3. HandlerMapping根据请求URL找到具体的Controller
  4. Controller处理请求,并返回ModelAndView,其中的View只是视图名,并不指向具体的视图组件
  5. DispatcherServlet通过ViewReslover(视图解析器)确定负责显示数据的具体View
  6. DispatcherServletView进行渲染视图(即将Model填充至视图组件中),并将完整的视图响应到客户端

@RequestMapping注解的作用是?

@RequestMapping注解是SpringMVC框架中提供的注解,是书写在Controller类里面的修饰方法的,用来配置处理的请求路径

@RequestBody注解的作用?

当客户端通过post请求提交的参数为⾃定义的JS对象时,接收参数时需要使用@RequestBody注解修饰接收参数的对象,否则接收到的参数为null

@RequestBody,@ResponseBody和@RequestMapping注解的作用是什么?

  • @RequestBody:当客户端通过post请求提交的参数为⾃定义的JS对象时,接收参数时需要使用@RequestBody注解修饰接收参数的对象
  • @ResponseBody:用来处理响应数据,添加完此注解后Controller中的方法可以通过返回值的方式给客户端响应数据
  • @RequestMapping:用来配置请求路径

Spring MVC常用注解有哪些?都有什么用?

  • @ResponseBody:添加在方法上,标记此方法是“响应正文”的,添加在类上,标记此类中所有方法都是“响应正文”的
  • @RestController:添加在类上,标记此类是一个“响应正文”的控制器类
  • @RequestMapping:添加在类上,也可以添加在处理请求的方法上,通常用于配置请求路径
  • @GetMapping:添加在方法上,是将请求方式限制为GET的@RequestMapping
  • @PostMapping:添加在方法上,是将请求方式限制为POST的@RequestMapping
  • @DeleteMapping:添加在方法上,是将请求方式限制为DELETE的@RequestMapping
  • @PutMapping:添加在方法上,是将请求方式限制为PUT的@RequestMapping
  • @RequestParam:添加在请求参数上,可以:1. 指定请求参数名称;2. 要求必须提交此参数;3. 指定请求参数的默认值
  • @PathVariable:添加在请求参数上,用于标记此参数的值来自URL中的占位符,如果URL中的占位符名称与方法的参数名称不同,需要配置此注解参数来指定URL中的占位符名称
  • @RequestBody:添加在请求参数上,用于标记此参数必须是对象格式的参数,如果未添加此注解,参数必须是FormData格式的
  • @ExceptionHandler:添加在方法上,标记此方法是处理异常的方法,可以通过配置注解参数来指定需要处理的异常类型,如果没有配置注解参数,所处理的异常类型取决于方法的参数列表中的异常类型
  • @ControllerAdvice:添加在类上,标记此类中特定的方法将作用于每次处理请求的过程中
  • @RestControllerAdvice:添加在类上,是@ControllerAdvice@ResponseBody的组合注解

Mybatis框架

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

  • Mybatis中的#{}格式的占位符是预编译的,即SQL语句会先经过词法分析、语义分析,再编译,当编译完成后,再将值代入到编译结果中一并执行!由于是预编译的,此前已经完成语义分析,语义是已经确定的,占位符的位置一直是某个值,不可能是字段名,所以,所有值都不需要使用单引号框住!并且,由于是预编译的,所以不存在SQL注入的问题!使用这种占位符时,占位符位置只能表示某个值!
  • Mybatis中的${}格式的占位符不是预编译的,即先将值代入到SQL语句中,然后,并代入后的结果再执行词法分析、语义分析、编译,最终执行!由于不是预编译的,而是先将值代入到SQL语句中,对于非数值、非布尔值的其它值而言,如果不加单引号,就会被误以为是字段名,所以,所有非数值、非布尔值的其它值都必须使用一对单引号框住!并且,由于不是预编译的,向SQL语句中传入的值有可能改变SQL的语义,是存在SQL注入风险的!使用这种占位符时,占位符位置可以表示SQL语句的任何片段!

MyBatis怎么防止SQL注入

使用#{}的方式是SQL编译预处理,能够防止SQL注入,而使用${}的方式是直接SQL拼接,存在SQL注入的风险,如果需要在使用${}时避免出现SQL注入,必须使用正则表达式对${}的参数值进行严格的检查。

MyBatis的一级缓存二级缓存?

  • Mybatis自带2级缓存机制,即Mybatis在满足特定的情况下,会将查询结果暂时保存起来,如果下次需要查询的与此前保存的结果是相同的,则下次并不会真正的查询,而是直接将此前缓存的结果返回,以提高查询效率!
  • Mybatis的一级缓存是基于SqlSession的,也称之为“会话缓存”,默认是开启的(不可控),基本上人为不可控,当使用同一个SqlSession,同一个Mapper,执行同样的SQL,并且SQL语句中需要传入的参数是相同的,则一级缓存是生效的!
    • 一级缓存会在以下情况失效:
      • 不满足使用条件:不是同一个SqlSession,或不是同一个Mapper,或不是同样的SQL,或不是同样的参数
      • 手动调用方法清除缓存:调用SqlSession对象的关闭或clearCache()方法
      • 当前Mapper执行了任何写操作,即使这个写操作与当前需要查询的数据无关,甚至这个写操作执行完毕后受影响的行数为0,也会清除一级缓存数据
  • Mybatis的二级缓存是基于namespace的,在Spring Boot项目中,默认是全局开启的(可控),但各namespace并未开启,二级缓存只需要同一个namespace、执行同样的SQL、传入同样的参数,就是有效的!
    • 如果是通过XML文件来配置SQL语句,需要在XML文件中添加<cache/>标签,以开启当前namespace的二级缓存!当在namespace中开启二级缓存后,还可以在各查询的<select>标签上配置useCache属性,如果取值为false,将对此查询不启用二级缓存!
    • 需要注意:启用二级缓存后,查询的返回结果类型必须实现Serializable接口!二级缓存也会因为当前namespace中执行了任何写操作而销毁!
  • Mybatis在执行查询时,会先从二级缓存中查找缓存数据,如果命中,则返回,如果未命中,则会从一级缓存中查找缓存数据,如果命中,则返回,如果仍未命中,则会执行真正的查询。

简述MyBatis的单个参数、多个参数如何声明?

  • 单个参数直接定义即可;
  • 使用@Param注解传递多个参数;通过Java Bean传递多个参数;使用Map封装多个参数

MyBatis 如何完成批量操作?

  • 在数据量不是特别大的情况下(不超过1000条,且每条数据都不是特别长),可以在XML拼接SQL,主要通过<foreach>标签对参数进行遍历。
  • 当数据量很大(通常超过500条甚至更多),并且非常关注执行效率的情况下,应该配置MybatisExecutorTypeBATCH来执行批处理操作。

MyBatis缓存优先级?

通过Mybatis 发起的查询,顺序为: 二级缓存 > 一级缓存 > 数据库

MyBatis和MyBatis Plus的区别

  • MyBatis 是一款优秀的持久层框架,它支持自定义 SQL,MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。
  • Mybatis-Plus是一个Mybatis的增强工具,它在Mybatis的基础上做了增强,却不做改变,在使用Mybatis-Plus之后既可以使用Mybatis-Plus的特有功能,又能够正常使用Mybatis的原生功能。

MyBatis如何实现分页?

通过SQL语句中的limit实现分页,或通过Mybatis分页插件PageHelper实现分页

写过原生的分页吗?用过什么插件吗?分页插件的原理?

  • 原生分页就是通过SQL语句中的limit实现分页
  • 使用插件的话,就是通过PageHelper实现分页
  • PageHeapler 通过MyBatis拦截器实现的分页,核心类是PageInterceptor,使用时,需要注意,设置分页与执行查询应该是连续的2条语句,不可以在中间添加if等代码,否则可能导致线程安全问题。

你知道MyBatis延迟加载吗?

  • mybatis的延迟加载就是按需查询,在需要的时候进行查询。
  • 在MyBatis的属性中配置:
    • lazyLoadingEnabled设置为true表示开启延迟加载,默认为false
    • aggressiveLazyLoading设置为false表示按需加载,默认为true

JDBC与Mybatis的区别,JDBC为什么效率比MyBatis快

  • JDBC是Java提供的操作数据库的API,JDBC的主要问题在于:编码工作量相对繁琐,模板化的代码太多。
  • Mybatis是基于JDBC实现的,能够通过反射将JDBC与Java对象映射,基本不用写JDBC代码。
  • 由于采用反射进行映射,性能比原生JDBC API略慢。

当数据库中表的字段和实体类中的属性名不⼀致时如何解决?

  • 可以通过ResultMap标签进行配置,
  • 可以在application.properties里面添加配置信息⾃动识别驼峰命名和数据库字段命名的区别,
  • 可以在查询数据时使用别名解决

什么是过滤器?

过滤器中的代码可以在请求到⽬标资源之前和之后执行,可将请求多个资源之前或之后执行的重复代码写在过滤器里面,从⽽达到代码重用的作用,使用过滤器可以提高开发效率

实现记住用户名和密码使用Cookie还是Session技术?为什么?

使用Cookie实现此功能, 因为保存数据的时间⼀般会很久,Session只能保存半小时左右的时间

介绍⼀下什么是Cookie?

  • 类似打孔会员卡, 数据保存在客户端
  • Cookie的数据默认是保存在浏览器的内存中,当⼀次会话结束时数据会清除
  • 可以设置任意的保存时长,设置了保存时间之后数据会保存到磁盘中,当时间到了之后再清除
  • 只能保存文本类型的数据数据量最多只能保存几k的数据
  • 应用场景: 需要长时间保存的和客户端相关的数据,比如:记住用户名和密码

介绍⼀下什么是Session?

  • 类似银行卡,数据保存在服务器内存中
  • Session保存数据的时间是半个小时左右
  • 可以修改但是不建议修改
  • 可以保存任意对象类型的数据数据量没有限制(但是不推荐保存⼤量数据,因为资源有限)
  • 应用场景: 对安全性要求较高并且和客户端相关的数据,比如记住登录状态
  • 因为Session保存数据时间过短, 不能用来记住用户名和密码

HTTPSession对象常用的方法有哪些?

HTTPSession对象的方法包括:

  • setAttribute("xxx",xxx):往会话对象中添加数据
  • getAttribute("xxx"):从会话对象中获取数据
  • removeAttribute("xxx"):删除会话对象中的数据

用户权限管理需要几张表?

权限管理总共涉及5张表:

  • 三张主表(用户表,⾓⾊表,权限表)
  • 两张关系表(用户⾓⾊关系表,⾓⾊权限关系表)

SpringBoot框架

SpringBoot框架的作用?

  • 如果创建⼀个空工程,在此工程中需要使用SSM框架时需要在工程中添加⼤量的依赖和书写⼤量的配置文件
  • 通过SpringBoot框架创建工程可以更加便捷的让工程中引入各种其它框架
  • SpringBoot框架的作用是帮助程序员构建工程的

Spring Boot自动配置原理

  • @EnableAutoConfiguration会读取工厂配置,即/META-INF/spring.factories
  • 然后找到标注@Configuration的配置类,配置类中使用@Conditional???系列注解,进行条件配置,根据条件初始化Bean组件,典型的注解有:
    • @ConditionalOnClass(当某个类存在时)
    • @ConditionalOnBean(当某个对象存在时)
    • @ConditionalOnMissingBean(当不存在某个对象时)
    • @ConditionalOnProperty(当存在某个属性的配置时)

Spring Boot常用注解有哪些?都有什么用?

  • @SpringBootApplication:添加在类上,用于标记此类是Spring Boot的启动类,每个Spring Boot项目应该只有1个类添加了此注解,这个注解的典型元注解包括@SpringBootConfiguration,所以Spring Boot项目的启动类本身也是配置类,并且,元注解中还包括@EnableAutoConfiguration,所以Spring Boot项目默认开启了自动配置,元注解中还包括@ComponentScan,但没有显式的配置根包,所以Spring Boot项目默认从启动类所在的包开始执行组件扫描
  • @SpringBootConfiguration:通常不需要显式的使用,它是@SpringBootApplication的元注解之一
  • @SpringBootTest:添加在类上,用于标记此类是加载Spring环境的测试类

8080端口被占用怎么解决?

关于端口占用问题:

  1. ⼀般情况下可以通过重启电脑解决端口占用问题
  2. 需要检查是不是有其它工程正在运行,如果有的话先关闭再运行新工程
  3. 可以通过在application.properties配置文件中添加修改端口的代码,解决端口占用问题
  4. 在命令行通过命令找到占用8080端口的进程id, 通过指令结束进程

SpringCloud框架

Spring、Spring MVC、Spring Cloud、Spring Boot的区别是什么?

  • Spring是一个轻量级的控制反转(IoC)和支持面向切面编程(AOP)的容器框架,是Spring全家桶的基石。
  • Spring MVC是建立在Spring基础之上的,是一个Web框架,使得开发Web应用变得很容易。
  • Spring Boot主要解决了依赖管理与自动配置相关问题,其思想是约定大于配置,极大的简化了项目中的配置,做到开箱即用。
  • Spring Cloud构建于Spring Boot之上,是一个微服务解决方案,包含了微服务相关问题的解决方案的框架,主流的Spring Cloud体系有Netflix的,其典型代表是使用Eureka处理服务发现,使用Zuul处理网关路由,使用Ribbon处理服务间通信,另一套主流的Spring Cloud体系是Alibaba的,其典型代码是使用Nacos处理服务发现并作为配置中心,使用Dubbo处理服务间通信。

Dubbo和HTTP Rest的区别

Dubbo和HTTP Rest都是常见的分布式系统中的RPC框架,二者的主要区别如下:

  • 通信协议不同:Dubbo使用TCP协议进行通信,而HTTP Rest则使用HTTP协议。
  • 序列化方式不同:Dubbo使用Hessian2、Java原生序列化、JSON等序列化方式,而HTTP Rest一般使用JSON作为数据传输的格式。
  • 传输方式不同:Dubbo采用点对点通信方式,即服务提供方与服务消费方之间建立连接,而HTTP Rest是一种无状态的通信方式,即每次请求都是相互独立的。
  • 服务治理能力不同:Dubbo提供了注册中心、负载均衡、服务降级、服务熔断等服务治理能力,而HTTP Rest则缺乏这些服务治理能力。
  • 性能差异:由于Dubbo采用二进制协议和自定义序列化方式,因此其性能一般比HTTP Rest更高效。

综上所述,Dubbo更适合高性能、高可靠性的分布式系统,而HTTP Rest更适合简单的、对性能要求不高的系统。

如何使用 Spring Cloud拆分应用?

使用 Spring Cloud 拆分应用可以将一个大型的单体应用拆分成多个小型的微服务,每个微服务负责一个特定的业务功能,可以独立部署、运行和扩展,从而实现更加灵活、可维护和可扩展的应用架构。

下面是使用 Spring Cloud 拆分应用的一般步骤:

  • 识别业务边界:将业务划分成多个小的领域模型,每个领域模型可以对应一个微服务。
  • 设计 API 网关:通过 API 网关来聚合微服务,实现跨域请求、负载均衡、路由和安全控制等功能。
  • 选择通信协议:选择合适的通信协议来实现微服务之间的通信,比如 HTTP、REST、RPC 等。
  • 配置注册中心:使用服务注册与发现机制来管理微服务的注册和发现,可以使用Spring Cloud Eureka、Consul、Zookeeper 等注册中心。
  • 配置服务发现:通过注册中心可以实现服务发现,即每个微服务可以查询注册中心获取其他微服务的信息。
  • 配置负载均衡:通过负载均衡算法来实现请求的均衡分发,可以使用 Ribbon、Nginx、HAProxy 等负载均衡工具。
  • 配置断路器:使用断路器模式来处理微服务之间的故障,可以使用 Hystrix 等断路器框架。
  • 配置配置中心:使用配置中心来管理微服务的配置信息,可以使用 Spring Cloud Config 等配置中心。

总的来说,使用 Spring Cloud 拆分应用可以实现高可用、高可扩展、高可维护的微服务架构。

Spring Cloud了解吗?谈谈你的理解?

  • 是的,我了解 Spring Cloud。Spring Cloud 是一个开源的分布式系统框架,它基于Spring Boot 构建,提供了一组分布式系统开发工具,包括服务发现、配置管理、负载均衡、断路器、消息总线等,帮助开发者快速构建分布式系统。
  • 使用 Spring Cloud 可以快速构建基于微服务的分布式系统,帮助开发者提高系统的可维护性、可扩展性和可靠性。同时,Spring Cloud 也为企业级应用开发提供了一种新的方式,使得开发者可以更加专注于业务逻辑的实现,而无需关注分布式系统开发中的技术细节。

Spring Cloud Alibaba中有哪些组件?

Spring Cloud Alibaba 是 Spring Cloud 的一个拓展,基于阿里巴巴的一些开源项目,包括 Nacos、Sentinel、RocketMQ、Dubbo 等,提供了一些分布式系统开发的解决方案。具体来说,Spring Cloud Alibaba 包括以下几个核心组件:

  • Nacos:服务注册与发现、配置管理、流量管理平台,支持 DNS 和 HTTP 协议。
  • Sentinel:流量控制、熔断降级、系统负载保护,支持多种规则模式。
  • RocketMQ:分布式消息中间件,提供消息发布订阅、点对点消息、顺序消息等多种消息模式。
  • Dubbo:分布式服务框架,支持多种协议、多种负载均衡、多种集群模式。
  • Spring Cloud Alibaba 还提供了一些其他的辅助组件,例如开发者工具、安全框架、分布式事务管理等。使用 Spring Cloud Alibaba,可以快速搭建一套分布式系统,并且支持与传统的 Spring Cloud 技术栈无缝集成,具有很好的扩展性和兼容性。

总的来说,Spring Cloud Alibaba 为开发者提供了一套完整的、可靠的分布式系统解决方案,可以提高系统的可维护性、可扩展性和可靠性,帮助开发者快速构建高性能的分布式系统。

限流是怎么做的?

限流是一种常用的流量控制方法,可以有效地控制系统的吞吐量,防止系统被过多的请求压垮。限流的实现方法有很多种,以下是几种比较常用的方法:

  • 令牌桶算法:令牌桶算法是一种固定容量的令牌桶,按照固定速率往桶里放入令牌。当请求到来时,需要先从桶中获取一个令牌,如果桶中没有令牌,则请求会被拒绝。
    • 这种算法可以平滑限流,但是需要额外的线程来定期放入令牌。
  • 漏桶算法:漏桶算法是一种固定容量的漏桶,按照固定速率流出水滴。当请求到来时,需要先往漏桶中加入一个水滴,如果漏桶已满,则请求会被拒绝。
    • 这种算法可以简单粗暴地限制流量,但是可能会导致短时间内的流量突发。
  • 计数器算法:计数器算法是一种简单的限流算法,通过记录每秒钟处理的请求数量,当请求数量达到阈值时,后续的请求会被拒绝。
    • 这种算法简单易用,但是无法平滑限流。
  • 基于令牌桶的框架:一些框架,如 Google Guava 和 Netflix Hystrix 等,提供了基于令牌桶算法的限流功能,可以方便地进行限流。

总的来说,限流是通过对请求进行计数、令牌桶、漏桶等方式进行限制,来控制系统的吞吐量,防止系统被过多的请求压垮。具体选择哪种算法,需要根据实际业务场景和系统特点进行选择。

Spring Cloud Alibaba 如何限流?熔断?降级?

在 Spring Cloud Alibaba 中,限流、熔断和降级都是通过Sentinel来实现的。

  • 限流:Sentinel 提供了流量控制的功能,可以通过限制每秒钟处理请求的数量或者每秒钟允许通过的 QPS(Queries Per Second)数量,来达到限流的目的。限流可以有效地保护系统的稳定性,防止系统被过多的请求压垮。
  • 熔断:熔断是一种在服务调用链路中解决雪崩效应的技术。在服务调用链路中,如果某个服务出现了问题,可能会导致后续的服务也出现问题,进而导致整个系统不可用。熔断机制会在服务出现问题时,及时断开该服务的调用,从而避免出现雪崩效应。Sentinel 提供了熔断降级的功能,可以设置一个阈值,当系统的请求超过这个阈值时,Sentinel 会触发熔断降级机制,避免系统的崩溃。
  • 降级:降级是一种在服务不可用时,为了保证系统的可用性而采取的一种措施。降级机制会在服务出现问题时,及时切换到备用方案或者返回预设的默认值,从而保证系统的稳定性。Sentinel 提供了降级的功能,可以设置一个阈值,当系统的请求超过这个阈值时,Sentinel 会触发降级机制,避免系统的崩溃。

总之,Sentinel 是一个功能强大的开源框架,可以帮助开发者在分布式系统中实现限流、熔断和降级等功能,保证系统的稳定性和可用性。

心跳机制

  • 心跳机制是指在网络通信中,发送一定的数据包(通常是心跳包),以维护连接的状态。它的主要目的是让通信双方持续保持连接,避免网络中断、超时等问题,保证数据传输的可靠性。
  • 在实际应用中,心跳机制通常被用来检测网络连接的存活状态,例如在客户端和服务器之间保持长连接时,客户端需要定期发送心跳包给服务器,以告知服务器自己的存活状态,同时也可以通过接收服务器的心跳包来判断服务器是否正常运行。
  • 在分布式系统中,心跳机制也被广泛应用,例如在服务注册中心、负载均衡器、集群管理器等组件中,通过心跳机制来检测各个节点的存活状态,实现高可用性、容错性等功能。

分布式

说说分布式事务?

分布式事务是指涉及到多个不同的计算机、进程或者服务之间的事务操作。在分布式环境中,需要多个节点之间协调执行事务,确保事务的正确性、一致性和完整性。

分布式事务的实现有多种方式,其中比较常见的包括以下几种:

  • 两阶段提交:在两阶段提交协议中,事务协调器向各参与节点发起预提交请求,并等待各参与节点的响应。当所有节点都反馈“同意”时,事务协调器向所有节点发起“提交”请求,各节点执行提交操作。如果有任何一个节点反馈“不同意”,则事务协调器向各节点发起“回滚”请求,各节点执行回滚操作。
  • TCC(Try-Confirm-Cancel):TCC是一种补偿型事务,它将一个大事务拆分成多个小事务,每个小事务都有对应的Try、Confirm、Cancel三个操作。在执行一个分布式事务时,首先执行Try操作,尝试执行业务逻辑,如果执行成功,则执行Confirm操作,将结果提交;如果执行失败,则执行Cancel操作,将结果回滚。
  • 消息队列:在分布式事务中,可以通过消息队列来实现事务的异步提交和回滚。当事务执行成功时,将需要执行的操作作为消息发送到消息队列中,如果消息发送失败,则事务回滚;当事务执行失败时,可以通过消息队列来执行回滚操作,以确保事务的正确性。
  • 最大努力通知:最大努力通知是一种基于重试的事务处理机制。在分布式事务中,将事务的执行结果异步通知给其他节点,如果通知失败,则进行重试。通过不断重试,可以最大限度地保证事务的正确性。

总的来说,分布式事务是一种复杂的问题,需要综合考虑多个方面的因素,包括系统的可用性、性能、复杂度等等。不同的实现方式有着各自的优缺点,需要根据实际场景和需求进行选择。

说说分布式锁

分布式锁是一种用于分布式系统中协调多个进程或者线程之间访问共享资源的一种锁机制。在分布式系统中,多个进程或线程同时访问共享资源时,需要一种机制来协调它们的访问,以避免冲突和数据不一致的问题。

分布式锁的实现方式有多种,其中比较常用的有:

  • 基于数据库:使用数据库中的行级锁或者乐观锁机制实现分布式锁。
  • 基于缓存:使用分布式缓存中的原子操作,例如 Redis 的 SETNX 或者 Memcached 的add 操作实现分布式锁。
  • 基于 ZooKeeper:使用 ZooKeeper 的临时有序节点实现分布式锁。

使用分布式锁的好处是可以确保分布式系统中的数据访问是线程安全的,避免因为数据不一致而导致的系统错误。但是分布式锁的实现也存在一些问题,例如锁的粒度过细会导致锁争用过多,锁的粒度过大则可能导致性能问题,另外在某些情况下分布式锁也可能存在死锁问题。因此,在实现分布式锁时需要考虑多方面的因素,避免引入新的问题。

CAP是什么?

CAP 是指在一个分布式系统中,Consistency(一致性)、Availability(可用性)和Partition tolerance(分区容错性)这三个特性无法同时保证,只能选择其中两个

  • Consistency(一致性)指的是所有节点在同一时间的数据是相同的。在一个分布式系统中,如果有多个节点同时对数据进行了更新操作,那么就需要保证这些节点最终得到的数据是相同的。
  • Availability(可用性)指的是系统能够在有限的时间内处理请求,并返回合理的结果。在一个分布式系统中,如果某个节点发生故障或者网络出现问题,系统仍然能够继续处理请求并返回结果。
  • Partition tolerance(分区容错性)指的是系统能够在出现网络分区的情况下继续工作,保证分布式系统的可用性和一致性。分区指的是网络分区,即分布式系统中某些节点之间的网络连接断开了。

由于 CAP 定理的存在,分布式系统设计者需要根据自己的业务需求来权衡这三个特性。在实际应用中,可能需要在一致性和可用性之间进行权衡,或者在可用性和分区容错性之间进行权衡。例如,在电商系统中,由于订单和库存等数据必须保持一致,因此可能需要在一致性和可用性之间进行权衡。而在社交网络或者新闻网站中,为了保证用户能够及时看到最新的动态或者消息,可能需要在可用性和分区容错性之间进行权衡。

消息队列

RabbitMQ使用,主要用在哪些场景?

RabbitMQ是一种开源的消息队列系统,它实现了高效的消息传递机制,主要应用于以下场景:

  • 异步处理:使用RabbitMQ可以将耗时的处理任务异步执行,使主流程不受阻塞,提升系统的并发性和吞吐量。
  • 应用解耦:通过RabbitMQ,不同应用之间可以使用消息进行通信,避免直接调用导致的耦合问题。
  • 流量削峰:当系统承受不住瞬间的高并发请求时,可以将请求先放到消息队列中,再由后台进行消费和处理。
  • 数据分发:使用RabbitMQ可以将同一个数据分发到多个消费者进行处理,保证数据的一致性和实时性。
  • 日志收集:将应用产生的日志通过RabbitMQ发送到日志收集系统进行集中存储和分析,方便进行系统监控和排查问题。

总之,RabbitMQ的应用场景非常广泛,可以用于分布式系统中的各种异步通信、解耦、削峰、流量控制等问题。

项目里RabbitMQ设置的消息过期时间是多久?过期时间太短怎么处理

  • 消息过期时间是在生产者发布消息时设置的,可以根据业务需求设置合适的过期时间。通常情况下,过期时间需要考虑消息的重要性、处理时间和消息队列的负载情况等因素,一般设置为几分钟或几小时。
  • 如果消息过期时间设置太短,可能会导致一些正常的消息被错误地丢弃,因此需要对过期时间进行调整。可以考虑以下几种解决方案:
    • 增加消息过期时间,确保消息在处理之前不会过期,但要注意不要设置过长的时间,以免占用队列过多的资源。
    • 优化消息消费端的处理速度,加快消费端的处理能力,尽快地处理消息,以减少消息的过期时间。
    • 对于重要的消息,可以在消息过期之前再次发送,以确保消息不会被丢失。
    • 调整消息队列的负载均衡,将消息分配到更少负载的队列上,以加快消息的处理速度。

RabbitMQ消息丢失怎么处理

当 RabbitMQ 中的消息丢失时,需要进行以下处理:

  • 检查 RabbitMQ 服务器状态,查看是否存在队列堵塞或者服务器宕机等问题。
  • 确认消息的发送和接收流程,查看是否存在消息发送到了错误的队列,或者消费者没有消费该队列等问题。
  • 检查消息的持久化设置,确保消息被正确地持久化,避免消息在服务器宕机等情况下丢失。
  • 考虑使用消息确认机制,例如开启 RabbitMQ 的确认模式,确保消息被正确地传递。
  • 考虑使用备份队列或者死信队列来处理消息丢失情况。
  • 此外,还可以通过日志或监控工具等方式记录 RabbitMQ 中消息的发送和接收情况,以及队列的状态和性能,以便更好地发现和解决问题。

项目

秒杀超卖问题

  • 秒杀超卖问题是指在秒杀活动中,由于并发请求过多,可能会导致某些商品卖超的情况。解决秒杀超卖问题的常见方法包括以下几种:
    • 限流措施:通过限制每个用户的请求频率或者通过对整个请求进行限制来减缓并发请求压力,从而避免商品卖超的情况。
    • 引入消息队列:将请求放到消息队列中,再由队列逐一处理请求,通过限制队列处理能力来避免并发请求对系统造成的压力,避免商品卖超的情况。
    • 乐观锁和悲观锁:乐观锁通过在数据记录中添加版本号或者时间戳来控制数据的并发更新,可以有效地避免脏数据的出现。悲观锁则是通过数据库锁机制来保证数据的一致性,但是会影响性能。
    • 随机延迟:通过在服务器端引入随机延迟,使得一些请求被延迟处理,从而避免瞬时的请求过载。
  • 以上解决方案都有各自的优缺点,在实际应用中需要根据具体情况进行选择。同时,在设计秒杀系统时,需要根据实际业务需求、系统负载能力等因素综合考虑,才能达到良好的效果。

秒杀模块怎么解决的高并发

秒杀活动一般会引起系统的高并发,为了解决这个问题,需要考虑以下几个方面:

  • 限流:通过限制每个用户的请求频率或者通过对整个请求进行限制来减缓并发请求压力,从而避免服务器崩溃。
  • 缓存:缓存热门商品的信息,减轻数据库压力,提高系统响应速度。可以使用Redis等缓存中间件实现。
  • 异步:通过将请求放到消息队列中,再由队列逐一处理请求,通过限制队列处理能力来避免并发请求对系统造成的压力,避免系统瘫痪。
  • 负载均衡:通过将请求分发到多台服务器中,均衡服务器的负载,提高系统并发能力。
  • 数据库优化:通过数据库优化技术,如建立索引、优化SQL语句、使用分库分表等技术,提高数据库处理性能,避免数据库成为瓶颈。

以上解决方案都有各自的优缺点,在实际应用中需要根据具体情况进行选择。同时,在设计秒杀系统时,需要根据实际业务需求、系统负载能力等因素综合考虑,才能达到良好的效果。

跨域问题产生的原因和解决办法

  • 跨域问题的产生是因为浏览器的同源策略限制了从一个源加载的文档或脚本如何与另一个源的资源进行交互。同源策略是一种安全机制,它可以防止恶意网站窃取用户数据或者执行恶意操作。
  • 同源指的是协议、域名、端口号完全一致,只要有任何一个不同,都会被认为是跨域。

以下是解决跨域问题的几种方式:

  • JSONP:利用script标签的src属性不受同源策略限制的特点,通过在服务器端动态生成JavaScript脚本,实现跨域传输数据。
  • CORS:通过在服务端设置响应头部,允许跨域访问,是一种比较安全的跨域解决方案。
  • 代理:将客户端请求发送到同源服务器,由同源服务器再将请求发送到跨域服务器,然后将跨域服务器的响应发送回客户端,实现跨域访问。
  • Websocket:通过建立一条全双工通信的通道,可以在客户端和服务器之间进行实时数据传输,绕过同源策略的限制。
  • Nginx反向代理:通过Nginx配置反向代理服务器,将客户端的请求转发到目标服务器,然后将响应发送回客户端,从而实现跨域访问。

需要注意的是,每种解决方案都有其优缺点,根据实际情况选择最适合的方式。同时,在实际开发中需要注意安全问题,避免产生潜在的安全隐患。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

今天你学Java了吗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值