知识点
网络协议模块
- 三次握手和四次挥手(开发)
- 为什么不是2次握手?
- 客户端先向服务端进行第一次握手,服务端向客户端进行第二次握手,表示收到请求,如果不进行第三次握手,服务端无法知道客户端是否接收到了信息
- 为什么挥手要4次?
- 因为TCP协议是面向连接协议
- 客户端想要释放连接,向服务端发起第一次挥手,服务端收到客户端的请求,向客户端发送第二次挥手,确认已经做好释放客户端连接的准备,客户端发送第三次挥手,将服务端的数据打包发送回服务端,服务端收到后,发送第四次挥手将客户端的数据打包发回客户端,此时连接断开
- 为什么不是2次握手?
- TCP和UDP的区别
- IP划分 子网区分 网关 路由
- DNS
- OIS(七层)
操作系统
- Linux指令 top、grep、ps、tail、head、more、less、chmod、mount、df
- docker
- 虚拟化和容器化的区别
- 虚拟化和容器化都是为了将一套应用程序所需的执行环境打包起来,建立一个独立环境,方便在不同的硬件中移动
- 虚拟化是以操作系统为中心,容器化是以应用程序为中心
- 虚拟机需要安装操作系统(安装Guest OS)才能执行应用程序,而容器内不需要安装操作系统就能执行应用程序
- docker指令 docker run、images、pull、start、rmi
- 虚拟化和容器化的区别
- Nginx
- 反向代理
- 客户端发来请求,先由反向代理服务器,然后按一定的规则分发到明确的服务器,而客户端不知道是哪台服务器
- 负载均衡
- Nginx接收请求并将收到的请求按照一定的规则分发到不同的服务器进行处理
- 轮询、随机、权重、一致性hash算法
- 正向代理
数据库模块
-
关系型数据库和非关系数据库的区别
- 关系型数据库以库表结构进行存储,非关系型数据库以k-v键值对结构进行存储
- 关系型数据库存在事务的概念,非关系型数据库没有事务这一概念,每个数据集都是原子级别的
- 关系型数据库必须先定义好结构才能添加数据,非关系型数据库不用预先定义,随时都能添加数据
-
MySQL和Oracle的区别
- MySQL和Oracle都是关系型数据库
- MySQL是一个开源、免费的数据库,Oracle是是一个收费的数据库
- MySQL使用用户名、密码、位置这三个参数来验证用户,Oracle使用用户名,密码,配置文件,本地身份验证,外部身份验证,高级安全增强功能来验证用户
- 与Oracle相比,MySQL没有表空间,角色管理,快照,同义词和包以及自动存储管理
-
数据库的三范式
- 1NF 保证数据不可再分
- 2NF 满足1NF,并且非主键必须依赖于主键属性
- 3NF 满足2NF,并且非主属性不能与非主属性之间有依赖关系,非主属性必须直接依赖于主属性,不能间接依赖主属性
-
常见的约束(5种)
- 主键约束 PRIMARY KEY
- 非空约束 NOT NULL
- 默认值约束 DEFAULT
- 外键约束 FOREIGN KEY
- 唯一约束 UNIQUE
-
char和varchar的区别
- char是定长,char如果插入的长度小于定义长度时,则用空格填充
- varchar是不定长,varchar小于定义长度时,还是按实际长度存储,插入多长就存多长
- char最大长度是255字符,varchar的最大长度是65535字符
- char会浪费空间,varchar更节省空间
- char的查找效率比varchar的查找效率更高
-
SQL的分类
-
DDL 数据定义语句 关键字 create、 alter、 drop
insert into 表名 valus (1001,"name"); update 表名 set 字段=值; delete from 表名 where 字段名 = 条件
-
DML 数据操作语句 关键字 insert 、update 、delete
-
DQL 数据查询语句 关键字 select
-
DCL 数据控制语句 关键字 grant、 revoke
-
-
分组和排序
- 分组group by 排序order by
- 正序 asc (默认)
- 逆序 desc
-
聚合函数(5种)
- sum() 求和
- max() 最大值
- min() 最小值
- avg() 平均值
- count() 个数
-
where和having的区别
- where是在分组之前对数据进行过滤
- having是在分组之后对数据进行过滤
- having之后可以使用聚合函数,而where不行
-
delete drop truncate区别
- delete是删除表中的数据 DML语句 可以通过事务回滚
- drop是将表中的结构删除 DDL语句 不能通过事务回滚
- truncate是将表结构删除后重新创建一个空表 DDL语句 不能通过事务回滚
-
内连接和外连接的区别
- 内连接返回的结果集是两个表中所有相匹配的数据,而舍弃不匹配的数据
- 外连接需要以一张表为基准表,显示基准表的全部信息,把舍弃的元素也保存在结果关系中,而在其他属性上null值
- 左外连接和右外连接的区别
- 左外连接以左边的表为基准表
- 右外连接以右边的表为基准表
- 左外连接和右外连接的区别
-
exists not exists all any some
- exists(SQL返回结果集为真)
- not exists(SQL不返回结果集为真或返回结果集为假)
- all查询满足所有条件
- any、some查询任何一个满足条件
- in和exists的区别
- 当查询两个表的大小相当时,用in 和 exists差别不大
- in适合于外表大而内表小的情况
- exists适合于外表小而内表大的情况,这样效率会更高
-
索引
- 索引的概念
- 对一列数据或者多列数据进行排序的一种数据结构
- 索引的种类
- 主键索引:数据列不允许重复,不允许为NULL,一个表只有一个主键。
- 唯一索引:数据列不允许重复,允许为NULL,一个表允许多个列创建唯一索引。
- 普通索引:基本的索引类型,没有唯一性的限制,允许为NULL值。
- 全文索引:是目前搜索引擎使用的一种关键技术,对文本的内容进行分词、搜索。
- 覆盖索引:查询列要被创建的索引覆盖,不必读取数据行。
- 联合索引:多列值组成一个索引,用于组合搜索,效率大于索引合并。
- 索引的优点和缺点
- 优点
- 加快数据的查询速度
- 缺点
- 创建和维护索引组要耗费时间,并且随着数据量的增加所耗费的时间也会增加
- 索引需要占磁盘空间
- 当对表中的数据进行增加、删除和修改的时候,索引也要动态维护,这样就降低了数据的维护速度
- 优点
- 索引的数据结构
- B+TREE
- 优点
- 稳定的I/O次数
- 扫描的效率更高
- 扫库的能力更强
- 区间范围查找能力更强
- InnoDB
- 支持事务
- 行级锁定
- 能缓存索引,也能够缓存数据
- 支持外键约束
- 对硬件要求比较高
- 在InnoDB引擎中,二级索引都会保存主键信息
- 支持分区和表空间
- Hash
- 特点
- 时间复杂度为O(1),查询速度较快
- 只支持等值查询,不支持范围查询
- 如果字段重复过多,会出现大量哈希冲突(采用拉链法解决,效率会降低)
- memory存储引擎
- 特点
- 联合索引的最左匹配原则
- 创建联合索引,以最左边的为准,只要查询条件中带有最左边的列,那么查询就会使用到索引
- SQL优化方案/如何避免/索引失效的情况------>避免索引失效 避免全表扫描
- 避免在索引列上使用函数、算数运算符
- 字符串加引号,避免出现隐式数据转换
- 不要使用前模糊
- 减少过滤的开销
- 不要使用负向查询
- 索引的建立原则------->如何建立索引
- 在合适的字段建立索引
- 频繁查询 不经常更新的字段上建立索引
- 在有序的字段上建立索引
- 使用联合索引代替单列索引(查询频繁 有序字段左置
- 在离散度比较高的字段建立索引 也就是重复度低的字段建立索引
- 聚簇索引和非聚簇索引/一级索引和二级索引/主键索引和辅助索引
- 聚簇索引 就是主键,也叫做一级索引(聚集索引)
- 非聚簇索引 非主键
- 聚簇索引的value存的是 当前这行数据在磁盘的地址
- 非聚簇索引的value存的是 主键的值
- 索引的概念
-
数据库安全
- SQL注入问题 如何避免
- 避免使用常见的数据库名和数据库结构
- 使用正则表达式进行过滤
- 保证数据库的安全
- 备份 冷备份和热备份
- 热备份针对归档模式的数据库,在数据库仍旧处于工作状态时进行备份
- 冷备份指在数据库关闭后,进行备份,适用于所有模式的数据库
- 读写分离 分库分表
- 读写分离主要是为了将数据库的读和写操作分不到不同的数据库节点上。主服务器负责写,从服务器负责读。
- 读写分离可以大幅提高读性能,小幅提高写的性能。因此,读写分离更适合单机并发读请求比较多的场景
- 分库分表是为了解决由于库、表数据量过大,而导致数据库性能持续下降的问题
- 数据库的主从复制
- MySQL 主从复制是指数据可以从一个MySQL数据库服务器主节点复制到一个或多个从节点
- SQL注入问题 如何避免
-
事务
- 事务的概念
- 由一条或者多条SQL组成的一个不可分割的整体单元
- ACID四大特性
- 原子性Atomicity
- 事务是不可分割的工作单位,事务中的操作要么全部成功要么全部失败
- 一致性Consistency
- 事务使数据库从一个一致性状态变换到另一个一致性状态
- 隔离性Isolation
- 一个事务的执行不能被另一个事务干扰
- 持久性Durability
- 一个事务一旦被提交,对数据库中的数据改变是永久的,接下来其他操作对其无影响
- 原子性Atomicity
- 三个并发问题
- 脏读
- A事务读取B事务尚未提交的更改数据,并在这个数据的基础上操作。如果恰巧B事务回滚,那么A事务读到的脏数据被称为脏读
- 不可重复读
- A事务在进行中,同时读取数据,B事务对一条数据进行了修改,A事务第二次进行读取,读到了B事务修改的数据,这2次数据不一致,被称为不可重复读
- 幻读
- 一个事务中A事务读取数据,同时B事务提交的新增数据,A事务再次读取时,数据的个数不同,被称为幻读
- 脏读
- 四个隔离级别 记住隔离级别对应解决的问题
- 读未提交
- 读已提交(默认隔离级别) 可以解决脏读问题
- 可重复读 可以解决不可重复读问题
- 可串行化 可以解决幻读问题
- redo undo log的作用
- Redo log是InnoDB存储引擎实现的,并不是所有存储引擎都有。支持崩溃恢复是InnoDB的一个特性
- Redo log记录的是“在某个数据页上做了什么修改”,属于物理日志
- Undo log记录了事务发生之前的数据状态,如果修改数据时出现异常,可以用Undo log进行回滚操作,属于逻辑日志
- 事务的概念
-
视图
- 视图的概念
- 将查询结果作为一张表保存在内存中,将这个查询结果看成一个整体的表结构
- 视图的概念
-
视图的优点/好处
- 优点
- 视图可以隐藏表结构,维护数据的安全
- 视图可以做到权限安全
- 缺点
- 操作视图会比直接操作表要慢,要尽量避免在大型数据表中创建视图
- 使用嵌套视图时,会重复访问基础表,存在性能损耗
- 视图不能索引,也不能有关联的触发器或默认值
- 优点
-
存储过程
- 存储过程的概念
- 相当于封装了一组SQL语句集,一次编译,永久调用
- 存储过程的概念
-
存储过程的优点和缺点
- 优点
- 能完成较复杂的判断和运算
- 可编程性强,灵活
- SQL编程的代码可重复使用
- 执行的速度相对快一些
- 减少网络之间的数据传输,节省开销
- 缺点
- 修改、维护存储过程较为繁琐
- 开发调试复杂
- 没办法应用缓存
- 不支持群集,数据库服务器无法水平扩展
- 优点
-
触发器
- 触发器的概念
- 触发器是一种对象,它能根据对表的操作时间,触发一些动作,这些动作可以是insert,update,delete等修改操作
-
锁(扩展)
- 锁的粒度
- 行锁 行锁是粒度中最小的级别
- 表锁 锁定整个表
- 页锁(扩展) 一次锁定一页。25个行锁可升级为一个页锁
- 共享锁 排他锁
- 共享锁(Share Locks,简记为S)又被称为读锁,其他用户可以并发读取数据,但任何事务都不能获取数据上的排他锁,直到已释放所有共享锁。
- 排它锁((Exclusive lock,简记为X锁))又称为写锁,若事务T对数据对象A加上X锁,则只允许T读取和修改A,其它任何事务都不能再对A加任何类型的锁,直到T释放A上的锁。
- 死锁
- 四个必要条件
- 互斥条件:一个资源每次只能被一个进程使用
- 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放
- 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺
- 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系
- 如何避免死锁
- 按同一顺序访问对象
- 避免事务中的用户交互
- 保持事务简短并在一个批处理中
- 使用低隔离级别
- 使用绑定连接
- 四个必要条件
- 乐观锁和悲观锁
- 悲观锁(Pessimistic Lock): 就是很悲观,每次去拿数据的时候都认为别人会修改。所以每次在拿数据的时候都会上锁。这样别人想拿数据就被挡住,直到悲观锁被释放,悲观锁中的共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程
- 乐观锁(Optimistic Lock): 就是很乐观,每次去拿数据的时候都认为别人不会修改。所以不会上锁,但是如果想要更新数据,则会在更新前检查在读取至更新这段时间别人有没有修改过这个数据。如果修改过,则重新读取,再次尝试更新,循环上述步骤直到更新成功(当然也允许更新失败的线程放弃操作),乐观锁适用于多读的应用类型,这样可以提高吞吐量
- 锁的粒度
Java
-
八种基本数据类型
- 字节型 byte
- 短整型 short
- 整型 int
- 长整型 long
- 单精度 float
- 双精度 double
- 字符型 char
- 布尔型 boolean
-
关键字
- break 跳出当前循环
- continue 跳出本次循环
- return 结束方法
- 四个权限修饰符 和其作用范围
- public 能在其他包中可见
- private 只能在当前类中可见
- protected 能在同一个包的子父类中可见
- default 能在同一个包中可见
- extends
- 作用是继承类
- 只能继承一个类
- implements
- 作用是实现接口
- 可以实现多个接口
- final
- 修饰类的时候 是最终类 不可以被继承
- 修饰方法 是最终方法 不可以被重写
- 修饰变量 就是一个常量 值不可以被改变
- final不能修饰抽象类
- static
-
&和&&的区别
- &连接的2个比较表达式,结果都是true,最终结果为true
- &&如果左边的比较表达式结果为false,那么不执行右边
-
switch中可以传入的数据类型有哪些
- int String
-
面向对象三大特征
- 封装
- 继承
- 多态
-
封装的好处
- 提高代码安全性
- 提高代码复用性
- 封装细节,便于修改内部代码,提高可维护性,实现高内聚
- 简化外部调用,便于调用者使用,便于扩展和协作,实现低耦合
-
this和super的区别
- this代表的是所属函数调用者对象
- super代表的是父类空间的引用
- this不需要继承关系也能使用
- super一定要继承关系才能使用
- this调用的是当前对象中的构造函数
- super调用的是父类中的构造函数
-
接口和抽象类的区别
- 相似
- 都不能被实例化
- 都可以包含抽象方法
- 不同
- 抽象类可以有普通方法
- 接口在jdk1.8之后可以有普通方法,但必须要被default修饰
- 抽象类中成员变量可以是各种类型
- 接口中的成员变量只能是public static final修饰的常量
- 抽象类可以包含构造函数,作用是完成抽象类的初始化
- 接口里不包含初始化代码块,抽象类可以包含初始化代码块
- 一个类只能继承一个抽象类,一个类可以实现多个接口
- 相似
-
重写和重载的区别
- 重写发生在父类与子类之间,重载发生在本类
- 重载的方法名必须相同,重写的方法名相同且返回值类型必须相同
- 重载的参数列表不同,重写的参数列表必须相同
-
编译时多态和运行时多态
- 方法重载都是编译时多态
- 方法覆盖表现出两种多态性,当对象引用本类实例时,为编译时多态,否则为运行时多态
-
多态的好处/优点
- 降低了代码之间的耦合
- 提高了程序的扩展性
- 可替代性
- 接口性
- 灵活性
- 简化性
-
String String Buffer String Builder的区别
- 三者都是用来处理字符串的
- 三个类都被final修饰,因此都是不可继承的
- String Builder与String Buffer有公共父类AbstractString Builder
- String的对象不可变,String Buffer和String Builder的对象是可变的
- String Builder执行速度最佳,String Buffer次之,String的执行速度最慢
- String、String Buffer线程安全,String Builder线程不安全
-
equals == hashcode 区别
-
==可以比较基本数据类型和引用数据类型 比较基本数据类型时比较值是否相等,比较引用数据类型时比较引用是否为同一个引用
-
equals不能去比较基本数据类型 如果没有进行重写,那么则比较引用是否为同一个引用
如果进行过了equals重写 则比较引用对象的内容
-
hashCode不能去比较基本数据类型 一般去比较对象是否不相等
两个对象的hashCode值相等 对象不一定相等
两个对象的hashCode值不相等 一定不是同一个对象
-
-
instanceof 关键字的作用
- 判断一个引用类型变量所指向的对象是否是一个类(或接口、抽象类、父类)的实例,即它左边的对象是否是它右边的类的实例,该运算符返回boolean类型的数据
-
什么是包装类?有哪些
-
基本数据类型所对应的引用数据类型
基本数据类型 对应的包装类 byte Byte short Short int Integer long Long char Character float Float double Double boolean Boolean
-
-
内存溢出和内存泄漏的区别
- 内存泄露是指程序在申请内存后,无法释放已申请的内存空间
- 内存溢出指程序申请内存时,没有足够的内存供申请者使用
- 内存泄漏的堆积最终会导致内存溢出
-
throw和throws的区别
- throw
- throw用在方法体内
- throw是具体向外抛异常的,抛出的是一个异常实例
- throw如果执行了,一定是抛出了某种异常
- throws
- throws用在方法的签名上,表示该方法可能会抛出某种异常
- throws声明了是哪种类型的异常,使它的调用者可以捕获这个异常
- throws表示可能出现,但不一定
- throw
-
final finally finalize 的区别
- final为关键字
- finally为区块标志,用于try语句中
- finalize()为方法
- final为用于标识常量的关键字,final标识的关键字存储在常量池中
- finally{}用于标识代码块,与try{ }进行配合,不论try中的代码执行完或没有执行完(这里指有异常),该代码块之中的程序必定会进行
- finalize()方法在Object中进行了定义,用于在对象“消失”时,由JVM进行调用,用于对对象进行垃圾回收
-
什么是双亲委派
- 每一个类加载器收到一个类加载请求,都不会先自己去加载,而是委托给自己的父类加载,如果父类加载器还存在它的父类加载器,则继续向上委托,直到达到最顶层的父类加载器,从最顶层的父类加载器开始进行类的加载,如果最顶层的类加载器找不到类的路径,又交给子类加载进行加载,依次进行递归
-
数组的优点和缺点
- 优点
- 查询快,通过下标直接查找,此时的时间复杂度为O(1)
- 可以随机访问其中元素
- 缺点
- 在中间添加、删除效率较慢,此时时间和空间复杂度为O(n)
- 大小固定,只能存储一种类型的数据
- 优点
IO流、反射
- IO流的分类
- 输入流和输出流
- 字符流和字节流
- 对象流
- 序列化和反序列化
- 序列化就是指把Java对象转换为字节序列的过程
- 反序列化就是指把字节序列恢复为Java对象的过程
- 浅克隆和深克隆的区别
- 浅克隆:对当前对象进行克隆,并克隆该对象所包含的8种基本数据类型和String类型属性
- 深克隆:深克隆是在浅克隆的基础上,递归地克隆除8种基本数据类型和String类型外的属性
- 反射的三种实现方式
- 每个类会有一个class属性
- Object类下有getClass方法
- Class 类下有个静态方法 forName()
- 反射的优点和缺点
- 优点
- 解耦合
- 提高代码性能和可操作性
- 缺点
- 反射操作性能不如直接操作
- 使用反射会模糊程序内部逻辑
- 使用反射会存在安全问题
- 优点
集合
- 集合和数组的区别
- 数组声明了它容纳的元素的类型,而集合不声明
- 数组是静态的,一个数组实例具有固定的大小,一旦创建了就无法改变容量了。而集合是可以动态扩展容量
- 数组的存放的类型只能是一种(基本类型/引用类型),集合存放的类型可以不是一种(不加泛型时添加的类型是Object)
- 数组是java语言中内置的数据类型,是线性排列的,执行效率或者类型检查都是最快的
- 集合和数组之间的转换(List)
- 集合转数组:使用集合的toArray(T[] array)
- 数组转集合:Arrays.asList()、使用Java8的Stream、使用Apache Commons Collections(需要导依赖)
- List和Set区别
- List 存储有序 可以存储重复的数据
- Set 存储无序 不可以存重复的数据
- ArrayList和LinkedList区别
- 对于随机index访问的get和set方法,一般ArrayList的速度要优于LinkedList
- 新增和删除元素,一般LinkedList的速度要优于ArrayList
- ArrayList是基于数组实现的集合
- ArrayList直接通过数组下标直接找到元素
- ArrayList在新增和删除元素时,可能扩容和复制数组
- ArrayList的空间浪费主要体现在在list列表的结尾预留一定的容量空间
- LinkedList是基于链表实现的集合
- LinkedList要移动指针遍历每个元素直到找到为止
- LinkedList实例化对象需要查询的时间外,只需要修改指针
- LinkedList的空间花费则体现在它的每一个元素都需要消耗相当的空间
- HashSet和TreeSet的区别
- HashSet不能保证元素的排列顺序,顺序有可能发生变化
- HashSet集合元素可以是null,但只能放入一个null
- HashSet底层是采用HashMap实现的
- HashSet底层是哈希表实现的
- TreeSet中的数据在遍历时可以是有序的,不允许放入null值
- TreeSet是通过TreeMap实现的,只不过Set用的只是Map的key
- TreeSet的底层实现是采用二叉树(红-黑树)的数据结构
- TreeSet的两个比较器
- Comparable接口 必须实现compareTo()方法
- Comparator接口 重写 compare(Object o1,Object o2) 方法
- HashMap jdk1.8和1.7的区别
- JDK1.8
- HashMap1.8的底层数据结构是数组+链表+红黑树
- 使用尾插法
- 扩容后不用再去计算哈希值
- Hash算法为异或hash右移16位
- 把null作为以一个Hash值为0的普通节点处理
- JDK1.7
- HashMap 1.7的底层数据结构是数组+链表
- 使用头插法
- 每次扩容后需要计算哈希值
- Hash算法较为复杂
- 单独写一个putForNull()方法处理
- JDK1.8
- HashMap和HashTable的区别
- 继承的父类不同
- HashMap线程不安全
- HashTable线程安全
- 包含的contains方法不同
- HashMap是允许key和value为null值的
- HashTable键值对都不能为空,否则报空指针异常
- 计算哈希值方式不同
- 扩容方式不同
- 解决hash冲突方式不同
- 如何使用一个线程安全的Map集合
- 使用HashTable
- 使用Collections.synchronizedHashMap
- 使用ConcurrentHashMap
- 了解一下ConcurrentHashMap
- 什么是迭代器 迭代器的作用
- 迭代器是一种设计模式,它是一个对象,他可以遍历并且选择序列中的一个对象,使开发人员可以忽视这个序列中的底层结构
多线程
- 线程和进程的区别 协程
- 进程是操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位
- 每个进程都有独立的代码和数据空间,程序之间的切换会有较大的开销;线程可以看做轻量级的进程,同一类线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器,线程之间切换的开销小
- 如果一个进程内有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成的;线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程
- 同一进程的线程共享本进程的地址空间和资源,而进程之间的地址空间和资源是相互独立的
- 进程:一个在内存中运行的应用程序
- 线程:进程中的一个执行任务(控制单元),负责当前进程中程序的执行
- 协程:协程基于线程,它是轻量级的线程
- 线程的实现方式
- 继承Thread类
- 实现Runnable接口
- 实现Callable接口
- 通过线程池创建线程
- 线程的生命周期 状态
- 新建状态(New)
- 就绪状态(Runnable)
- 运行状态(Running)
- 阻塞状态(Blocked)
- 死亡状态(Dead)
- 线程池 优点 基本参数 JDK的几种线程池
- 优点
- 降低资源消耗
- 提高响应速度
- 提高线程的可管理性
- 基本参数
- corePoolSize:线程池中的常驻核心线程数
- maxinumPoolSize:线程池中能够容纳同时执行的最大线程数,此值必须大于等于一
- keepAliveTime:多余的空闲线程的存活时间
- unit:keepAliveTime的单位
- workQueue:任务队列,被提交但是尚未被执行的任务
- threadFactory:表示生成线程池中工作线程的线程工厂,用于创建线程一般用默认的即可
- handler:拒绝策略,表示当队列满了并且工作线程-大于等于线程池的数量最大线程数(maxinumPoolSize)时如何来拒绝请求执行的runnable的策略
- JDK的几种线程池
- newFixedThreadPool
- newSingleThreadExecutor
- newCachedThreadPool
- newScheduledThreadPool
- 优点
- 守护线程 和主线程
- 守护线程,只要其它非守护线程运行结束了,即使守护线程的代码没有执行完,也会强制结束
- start()和run()区别
- 当程序调用start()方法,将会创建一个新线程去执行run()方法中的代码
- 直接调用run()方法的话,会直接在当前线程中执行run()中的代码
- 当一个线程启动之后,不能重复调用start(),但是可以重复调用run()方法
- sleep() wait() join() yield() 四个方法
- sleep()方法属于Thread类,sleep过程中线程不会释放锁,只会阻塞线程,到达指定时间会自动恢复运行状态
- wait()方法属于Object类,wait过程中线程会释放锁,只有当其他线程调用 notify才能唤醒此线程,wait 使用必须在 synchronized 修饰的代码块中使用
- yield()方法属于Thread类,yield不会释放锁,让线程重新进入就绪状态
- 等待调用join方法的线程结束之后,程序再继续执行,一般用于等待异步线程执行完结果之后才能继续运行的场景
- 线程的同步和异步 阻塞和非阻塞
- 同步:调用某个东西时,调用方得等待这个调用返回结果才能继续往后执行
- 异步:调用方不会立即得到结果,而是在调用发出后调用者可用继续执行后续操作,通过回调函数来处理这个调用
- 阻塞:是指调用结果返回之前,当前线程会被挂起
- 非阻塞:没有一个线程可以妨碍其他线程执行
- synchronized 关键字 和 volatile关键字的作用
- 用synchronized修饰表示这个方法或代码块为同步的,在运行过程中会上同步锁
- volatile保证了共享变量的“可见性”
- volatile防止指令重排序
JVM虚拟机、JDBC
- JVM的内存划分 线程私有 共享 每一块内存是做什么的
- 线程共享
- 元空间 存储类的信息、静态变量、常量以及编译器编译后的代码
- 堆 存放对象实例
- 线程私有
- 虚拟机栈 存储局部变量表、操作数栈、动态链表、方法出口等信息
- 本地方法栈
- 程序计数器
- 线程共享
- 对象的引用级别 每个引用级别的特点
- 强
- 不会被GC进行回收
- 软
- 软引用指向的对象会在内存不足时被垃圾回收清理掉
- 软引用可以有效的解决OOM问题
- JVM会优先回收长时间闲置不用的软引用对象,对那些刚刚构建的或刚刚使用过的软引用对象会尽可能保留
- 弱
- 弱引用不能延长对象的生命周期,一旦对象只剩下弱引用,它就随时可能会被回收
- 可以通过弱引用获取对象的强引用
- 弱引用适合用作缓存
- 虚
- 虚引用不会影响对象的生命周期
- 虚引用可以用来做为对象是否存活的监控
- 强
- 如何判断对象是否可回收
- Java的内存管理子系统,是通过可达性分析算法来判定对象是否存活
- 或者通过引用计数法判断
- Minor GC 和 Full GC
- Minor GC:指的是发生在新生代的垃圾收集动作
- Full GC:指发生在老年代的GC
- 标记清除算法 标记整理算法 复制算法
- 标记清除:如果定位找到了垃圾对象 , 那么将该垃圾对象进行标记 ,标记好之后 , 在执行 GC 内存回收时 , 会将被标记的内存回收
- 标记整理:内存回收后 , 将内存中的对象重新紧密地排列 , 消除内存碎片
- 复制算法:对象只放在左侧区域 , 右侧区域空着,左侧区域的垃圾对象回收后 , 将存活的对象 , 拷贝到右侧区域中
- JDBC的执行流程
- 加载驱动
- 建立连接
- 创建语句
- 执行语句
- 处理结果
- 释放资源
- JDBC的缺点
- 需要频繁的创建数据库连接
- 涉及到的增删改查等功能需要在各个java文件中编写大量代码
- 对于底层事务、数据类型转换等都需要手动处理
- mybatis优点
- 封装了JDBC对数据库的各种操作,减少代码
- 增加了连接池、一、二级缓
- 可以自动生成sql语句
- 占位符和拼接符的区别
- # 将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。
- $ 将传入的数据直接显式生成在sql中。
- # 方式能够很大程度防止sql注入, ∗ ∗ 方式无法防止 S Q L 注入; ∗ ∗ ** 方式无法防止SQL注入;** ∗∗方式无法防止SQL注入;∗∗ 方式一般用于传入数据库对象,例如传入表名
servlet
- servlet生命周期和实现方式
- 加载 启动项目 读取web.xml
- init 方法 实例化 只能调用一次
- service方法 (可以调用多次) doGet/doPost
- destroy 销毁
- get请求和post请求的区别
- GET提交的数据放在URL中,POST则不会,GET比POST更不安全
- GET回退浏览器无害,POST会再次提交请求(GET方法回退后浏览器再缓存中拿结果,POST每次都会创建新资源)
- GET提交的数据大小有限制(是因为浏览器对URL的长度有限制,GET本身没有限制),POST没有
- GET能被缓存,POST不能
- GET只允许ASCII字符,POST没有限制
- Ajax的概念,优缺点
- 在页面不刷新的情况下,发送http请求,得到http响应
- 优点
- 可以实现局部刷新页面
- 缺点
- 如果网速慢,则会出现ajax请求缓慢,页面空白的情况,对客户的体验不好
- ajax请求不利于搜索引擎优化
- session的工作原理和cookie的区别
- cookie保存在浏览器端,session保存在服务端
- cookie如果在浏览器端对cookie进行设置对应的时间,则cookie保存在本地硬盘中,此时如果没有过期,则就可以使用,如果过期则就删除。如果没有对cookie设置时间,则默认关闭浏览器,则cookie就会删除。
session:我们在请求中,如果发送的请求中存在sessionId,则就会找到对应的session对象,如果不存在sessionId,则在服务器端就会创建一个session对象,并且将sessionId返回给浏览器,可以将其放到cookie中,进行传输,如果浏览器不支持cookie,则应该将其通过encodeURL(sessionID)进行调用,然后放到url中。 - cookie只能存储字符串,而session存储结构是k-v的结构,可以存放任何类型
- cookie最多可以存放
4k
大小的内容,session则没有限制 - session的安全性要高于cookie
- cookie的大小受限制,cookie不安全,如果用户禁用cookie则无法使用cookie。如果过多的依赖session,当很多用户同时登陆的时候,此时服务器压力过大。sessionId存放在cookie中,此时如果对于一些浏览器不支持cookie,此时还需要改写代码,将sessionID放到url中,也是不安全
- servlet和jsp的区别
- jsp经编译后就变成了Servlet
- jsp更擅长表现于页面显示,servlet更擅长于逻辑控制
- Servlet中没有内置对象,Jsp中的内置对象都是必须通过HttpServletRequest对象,HttpServletResponse对象以及HttpServlet对象得到
- 转发和重定向的区别
- 相同点
- 页面都会实现转跳
- 不同点
- 转发,url不会变化
- 重定向发送两次请求,url会变化
- 相同点
- 过滤器的概念和作用
- 当访问服务器的资源时,过滤器可以将请求拦截下来,然后完成一些特殊的功能
Spring
- spring概念
- spring是一个轻量级的开源框架。
- spring为了解决企业级应用开发的业务逻辑层和其他各层的耦合问题
- spring是一个IOC和AOP的容器框架
- 优点
- 轻量级框,数据大小很小
- 控制反转(IOC),实现松耦合
- 面向切面编程(AOP),实现了0侵入式编程
- 容器:bean factory和application context实现了对象的依赖管理和生命周期管理
- MVC框架
- 事物处理:声明式事务管理:可以将业务代码和事务管理分离,用注解和xml配置来管理事务
- 异常处理
- 什么是IOC和AOP
- IOC
- 控制反转
- 利用反射的原理将创建对象的权利交给Spring容器,spring在运行的时候根据配置文件来动态的创建对象和维护对象之间的关系
- AOP
- 面向切面编程
- 是一种通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术
- IOC
- 什么是DI
- 在运行过程中 把所依赖的对象动态的注入到程序中
- 依赖注入的方式有几种
- 属性(setter)注入,构造器注入,静态工厂方法注入,实例工厂方法注入
- byName 和 byType注入的区别
- byName就是通过Bean的属性名称(id或name)自动装配
- 将查找其类中所有的set方法名,例如setCat,获得将set去掉并且首字母小写的字符串,即cat
- 去spring容器中寻找是否有此字符串名称id的对象
- 如果有,就取出注入;如果没有,就报空指针异常
- byName就是通过Bean的Class类型来自动装配
- 同一类型的对象,在spring容器中唯一
- 如果不唯一,会报不唯一的异常
- @Bean 和 @Component
- 两者都是用来定义bean的方式
- @Component: 作用于类上,告知Spring,为这个类创建Bean
- @Bean:主要作用于方法上,告知Spring,这个方法会返回一个对象,且要注册在Spring的上下文中。通常方法体中包含产生Bean的逻辑。 相当于xml文件的中标签
- spring bean 的生命周期
- 实例化 Instantiation
- 属性赋值 Populate
- 初始化 Initialization
- 销毁 Destruction
- spring bean的作用域
singleton
: 唯一 bean 实例,Spring 中的 bean 默认都是单例的prototype
: 每次请求都会创建一个新的 bean 实例request
: 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP request 内有效session
: 每一次 HTTP 请求都会产生一个新的 bean,该 bean 仅在当前 HTTP session 内有效global-session
: 全局 session 作用域,仅仅在基于 Portlet 的 web 应用中才有意义,Spring5 已经没有了
- spring 的事务管理
- 编程式事务管理
- 通过
TransactionTemplate
或者TransactionManager
手动管理事务
- 通过
- 声明式事务管理
- 使用
@Transactional
注解进行事务管理
- 使用
- 编程式事务管理
- BeanFactory 和ApplicationContext的区别
- BeanFactory是Spring里面最低层的接口,提供了最简单的容器的功能,只提供了实例化对象和拿对象的功能
- BeanFactory在启动的时候不会去实例化Bean,中有从容器中拿Bean的时候才会去实例化
- ApplicationContext继承BeanFactory接口,它是Spring的一各更高级的容器,提供了更多的有用的功能
- ApplicationContext在启动的时候就把所有的Bean全部实例化了
- 国际化
- 访问资源,如URL和文件
- 载入多个(有继承关系)上下文 ,使得每一个上下文都专注于一个特定的层次
- 消息发送、响应机制
- AOP(拦截器)
- AOP的几种通知
- 前置通知
Before advice
:在连接点前面执行,前置通知不会影响连接点的执行,除非此处抛出异常 - 后置通知
After returning advice
:在连接点正常执行完成后执行,如果连接点抛出异常,则不会执行 - 异常通知
After throwing advice
:在连接点抛出异常后执行 - 最终通知
After (finally) advice
:在连接点执行完成后执行,不管是正常执行完成,还是抛出异常,都会执行返回通知中的内容 - 环绕通知
Around advice
:环绕通知围绕在连接点前后,能在方法调用前后自定义一些操作,还需要负责决定是继续处理join point
(调用ProceedingJoinPoint
的proceed
方法)还是中断执行
- 前置通知
- AOP的优点和应用
- 优点
- 减少重复代码
- 提高开发效率
- 维护方便
- 应用
- 权限判断:在执行方法前,判断是否具有权限
- 切面日志:在执行前进行日志处理
- 优点
SpringMVC
- 执行流程
- 用户发送请求至前端控制器DispatcherServlet
- DispatcherServlet收到请求调用HandlerMapping处理器映射器
- 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找),生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet
- DispatcherServlet调用HandlerAdapter处理器适配器
- HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)
- Controller执行完成返回ModelAndView
- HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet
- DispatcherServlet将ModelAndView传给ViewReslover视图解析器
- ViewReslover解析后返回具体View
- DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中),DispatcherServlet响应用户
- @RequestMapping注解的作用
- URL路径,将http的请求地址映射到控制器(controller)类的处理方法上
- @RequestMapping注解可以定义在控制器类上,也可以定义在类里面的方法上
- @ResponseBody @RequestBody作用
- @RequestBody
- 该注解用于读取Request请求的body部分数据,使用系统默认配置的HttpMessageConverter进行解析,然后把相应的数据绑定到要返回的对象上
- 再把HttpMessageConverter返回的对象数据绑定到 controller中方法的参数上
- @ResponseBody
- 该注解用于将Controller的方法返回的对象,通过适当的HttpMessageConverter转换为指定格式后,写入到Response对象的body数据区
- @RequestBody
- @RequestParam @PathVariable区别
- @PathVariable和@RequestParam都是用来获取前端通过URL传送到后端的参数
- @PathVariable获取的是URL中的占位符参数
- @RequestParam获取的是Request中的参数
- RestFul 风格的API接口的好处
- 前后端分离,减少流量
- 安全问题集中在接口上,由于接受json格式,防止了注入型等安全问题
- 前端无关化,后端只负责数据处理,前端表现方式可以是任何前端语言(android,IOS,html5)
- 前端和后端人员更加专注于各自开发,只需接口文档便可完成前后端交互,无需过多相互了解
- 服务器性能优化:由于前端是静态页面,通过Nginx便可获取,服务器主要压力放在了接口上
- 拦截器的作用
- 可以构成拦截器栈,完成特定功能。比如日志记录、登录判断、权限检查等作用
- 拦截器也可以让你将通用的代码模块化并作为可重用的类
MyBatis
- 执行流程
- 加载MyBatis的配置文件
- 加载映射文件
- 构造sqlsessionfactory
- 创建sqlsession
- 执行sql
- 返回一个结果
- 提交结果
- 关闭sqlsession对象
- 接口和xml文件的映射
- 映射文件中的namespace是对应接口的类路径
- 每个标签的id属性是接口里的方法名
- result type是返回类型
- param type是传入类型
- 动态sql标签
- where
- if
- choose one
- otherwise
- foreach
- 一级缓存 二级缓存
- 一级缓存默认开启,session级别
- 二级缓存手动开启,跨session级别,mapper级别缓存
- 二级缓存数据存放在一级缓存中
- 一级缓存提交或关闭,提交二级缓存
- 全自动ORM和半自动ORM的区别
- 相似点
- 二者都是优秀的持久层框架,帮助开发人员简化了开发工作
- 都是对
JDBC
进行封装 - 都是通过
SessionFactory
创建session
对象,由session
对象执行对数据库的操作语句
- 不同点
Mybatis
是半自动的映射持久层框架;Hibernate
是全自动的映射持久层框架Hibernate
不需要手动编写SQL,只需要操作相应对象即可,大大降低了对象与数据库的耦合性,而Mybatis
需要手动编写 SQL,可移植性Hibernate
比Mybatis
更高Mybatis
支持动态SQL,处理列表,存储过程,开发工作量相对大些;Hibernate
提供了HQL
操作数据库,如果项目需要支持多种数据库,代码开发量少,但 SQL语句的优化困难Mybaits
入门简单,即学即用;Hibernate
学习门槛相对较高
- 相似点
- MyBatis的优点
- 封装了JDBC对数据库的各种操作,减少代码
- 增加了连接池、一、二级缓存
- 可以自动生成sql语句
- 静态代理和动态代理 和cglib的区别
- 静态代理是最简单的代理模式。需要定义一个接口,然后委托类和代理类分别实现这个接口
- 动态代理需要实现接口,而cglib是通过继承来实现的,不需要定义接口
SpringBoot
- 优点
- 为所有Spring开发者更快的入门
- 开箱即用,远离繁琐的配置
- 内嵌式容器简化Web项目
- 约定大于配置
- 自动装配原理
- 扫描约定目录下的文件进行解析,解析完成之后把得到的Configuration配置类通过ImportSelector 进行导入,从而完成Bean的自动装配
Redis
- 非关系型数据库的作用
- 缓存
- redis的五种常用数据类型
- string
- hash
- set
- zset
- list
- 两种持久化机制
- RDB
- 可以配置持久化策略:save N M,让redis在“N秒内至少有M个改动”才会触发一次RDB持久化操作
- 优点
- 因为dump.rdb文件是二进制文件,所以当redis服务崩溃恢复的时候,能很快的将文件数据恢复到内存之中
- 缺点
- RDB每次持久化需要将所有内存数据写入文件,然后替换原有文件,当内存数据量很大的时候,频繁的生成快照会很耗性能
- 如果将生成快照的策略设置的时间间隔很大,会导致redis宕机的时候丢失过的的数据
- AOF
- 在使用AOF方式时,redis每执行一次修改数据命令,都会将该命令追加到appendonly.aof文件中(先写入os cache,然后通过fsync刷盘)
- 优点
- 优先级高
- 缺点
- 占用磁盘空间大
- 磁盘恢复速度慢
- 优点
- 在使用AOF方式时,redis每执行一次修改数据命令,都会将该命令追加到appendonly.aof文件中(先写入os cache,然后通过fsync刷盘)
- redis4.0 开始支持混合持久化
- 如果开启了混合持久化,AOF在重写时,不再是单纯将内存数据转换为RESP命令写入AOF文件,而是将重写这一刻之前的内存做RDB快照处理,并且将RDB快照内容和增量的AOF修改内存数据的命令存在一起,都写入新的AOF文件,新的文件一开始不叫appendonly.aof,等到重写完新的AOF文件才会进行改名,覆盖原有的AOF文件,完成新旧两个AOF文件的替换
- RDB
- redis的主从复制和哨兵机制
- 主从复制是主机数据更新后根据配置和策略, 自动同步到备机的master/slave机制,Master以写为主,Slave以读为主
- 数据冗余
- 故障恢复
- 负载均衡
- 高可用基石
- 能够后台监控主机是否故障,如果故障了根据投票数自动将从机转换为主机,通过哨兵服务器监控master/slave可以实现主从复制集群的自动管理
- 主观下线和客观下线
- 主服务器宕机,哨兵1先检测到这个结果,系统并不会马上进行failover过程,仅仅是哨兵1主观的认为主服务器不可用,这个现象成为主观下线
- 当后面的哨兵也检测到主服务器不可用,并且数量达到一定值时,那么哨兵之间就会进行一次投票,投票的结果由一个哨兵发起,进行failover操作。切换成功后,就会通过发布订阅模式,让各个哨兵把自己监控的从服务器实现切换主机,这个过程称为客观下线
- 缓存穿透
- 缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大
- 缓存击穿
- 缓存击穿实际上是缓存雪崩的一个特例,缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力
- 缓存雪崩
- 因为缓存服务挂掉或者热点缓存失效,所有请求都去查数据库,导致数据库连接不够或者数据库处理不过来,从而导致整个系统不可用
- 缓存预热
- 缓存预热就是系统启动前,提前将相关的缓存数据直接加载到缓存系统
- redis除了缓存 还能做什么.
- 任务队列
- 分布式锁
- 计数器控制
- 好友推荐
- 会话存储
- redis的单线程 为什么效率高
- redis是在内存上进行操作的
- 使用了高效的数据结构
- 采用了多路复用机制,使其在网络 IO 操作中能并发处理大量的客户端请求,实现高吞吐率
有的AOF文件,完成新旧两个AOF文件的替换
- redis的主从复制和哨兵机制
- 主从复制是主机数据更新后根据配置和策略, 自动同步到备机的master/slave机制,Master以写为主,Slave以读为主
- 数据冗余
- 故障恢复
- 负载均衡
- 高可用基石
- 能够后台监控主机是否故障,如果故障了根据投票数自动将从机转换为主机,通过哨兵服务器监控master/slave可以实现主从复制集群的自动管理
- 主观下线和客观下线
- 主服务器宕机,哨兵1先检测到这个结果,系统并不会马上进行failover过程,仅仅是哨兵1主观的认为主服务器不可用,这个现象成为主观下线
- 当后面的哨兵也检测到主服务器不可用,并且数量达到一定值时,那么哨兵之间就会进行一次投票,投票的结果由一个哨兵发起,进行failover操作。切换成功后,就会通过发布订阅模式,让各个哨兵把自己监控的从服务器实现切换主机,这个过程称为客观下线
- 缓存穿透
- 缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大
- 缓存击穿
- 缓存击穿实际上是缓存雪崩的一个特例,缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力
- 缓存雪崩
- 因为缓存服务挂掉或者热点缓存失效,所有请求都去查数据库,导致数据库连接不够或者数据库处理不过来,从而导致整个系统不可用
- 缓存预热
- 缓存预热就是系统启动前,提前将相关的缓存数据直接加载到缓存系统
- redis除了缓存 还能做什么.
- 任务队列
- 分布式锁
- 计数器控制
- 好友推荐
- 会话存储
- redis的单线程 为什么效率高
- redis是在内存上进行操作的
- 使用了高效的数据结构
- 采用了多路复用机制,使其在网络 IO 操作中能并发处理大量的客户端请求,实现高吞吐率