Java中有哪些集合

Java中的集合可以分为4类,使用4个接口代表,分别是List Set Queue Map。其中List Set Queue都继承自Collection。
List:是有序可重复集合,元素可为空,常用的有ArrayList(默认长度为10,扩容时是创先一个新的数组,将旧的数组中元素拷贝到新数组中,默认情况下扩容为原来长度的1.5倍) LinkedList
Set: 无序不可重复集合 元素可为空,常用的有HashSet TreeSet
Queue: 先进先出的队列,常用的有ArrayDeque
Map:键值映射关系,键值可为空,常用的有HashMap TreeMap HashTable

JVM内存模型

GC堆:线程共享,用来存储创建的实例对象和数组,划分成新年代和老年代,大多数对象创建完成后都是在新生代里,大对象是直接存储到老年代里,新生代的GC算法是标记复制,进行的区域是eden+s0或s1,比例是8:1:1,老年代GC算法是标记整理,新生代与老年代的空间比例默认是1:2
方法区:线程共享,存储JVM加载类时的类,常量,静态变量等信息,1.8后也叫元数据区
JVM栈:线程独有,主要作用是参与java运行,保存方法的局部变量,部分结果,参与方法的调用和返回,栈帧对应着一个个方法的调用
本地方法栈:作用与JVM栈类似,主要针对的native方法
程序计数器:记录JVM运行的字节码指令地址

垃圾定义算法

引用计数算法:在每个对象中添加一个引用计数器,有一个引用就加一,引用失效减一,计数器为0是不能再被使用的,存在循环引用问题
可达性分析算法:以GC Roots的根对象根据引用关系向下检索,当某个对象不可达时,则此对象不再被使用

垃圾回收算法

标记清除:最早最基础的算法,首先标记出要回收的对象,标记完成后统一回收被标记的对象;
缺点:
1、执行效率不稳定,随着对象数量的增多,标记次数增多,清楚也变多,执行效率下降
2、内存空间碎片化,导致空间浪费。
标记复制:把内存空间分成两块空间,每次只使用其中一块,将存活的对象复制到另一块空间,假如说大量的对象被回收,只需要复制一小部分即可,所以适用于新生代;
缺点:
资源利用低,衍生出半复制算法。eden + s比例为8:1,若s中放不下,则使用逃生门,将要复制的对象放入老年代里
标记整理:将存活的对象向内存的一端整理到一起,解决碎片化问题

Bean的生命周期

1.实例化对象 调用createBeanInstance()
2.设置属性并复制 调用popularBean()
3.初始化 调用initializeBean()
4.销毁

类加载机制

1.加载:通过全限定名定位类,读取class元数据信息保存在方法区,在堆中创建对应对象
2.验证:文件格式,元数据和方法体是否符合Java规范,符号引用是否能找到对应的类
3.准备:给静态变量分配内存并设置初始值
4.解析:符号引用转为直接引用,主要解析类或接口、字段、方法的句柄引用
5.初始化:执行类构造器cinit()

bean的浅拷贝和深拷贝

引用拷贝:创建一个引用变量指向同一个对象,地址是相同的
对象拷贝:新建了一个对象,地址不同
浅拷贝:属于对象拷贝,被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象,即对象的浅拷贝会对“主”对象进行拷贝,但不会复制主对象里面的对象。”里面的对象“会在原来的对象和它的副本之间共享,使用BeanUtils.copyProperties
深拷贝:是一个整个独立的对象拷贝,深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相比于浅拷贝速度较慢并且花销较大,可以使用构造方法或者重载clone方法进行深拷贝

SpringBoot启动流程

创建springbootApplication对象

  1. 创建springbootApplication对象springboot容器初始化操作
  2. 获取当前应用的启动类型。
    2.1:通过判断当前classpath是否加载servlet类,返回servlet web启动方式。
    2.2:webApplicationType三种类型:
    1.reactive:响应式启动(spring5新特性)
    2.none:即不嵌入web容器启动(springboot放在外部服务器运行 )
    3.servlet:基于web容器进行启动
  3. 读取springboot下的META-INFO/spring.factories文件,获取对应的ApplicationContextInitializer装配到集合
  4. 读取springboot下的META-INFO/spring.factories文件,获取对应的ApplicationListener装配到集合
  5. mainApplicationClass,获取当前运行的主函数

调用springbootApplication对象的run方法,实现启动,返回当前容器的上下文

  1. StopWatch stopWatch = new StopWatch(),记录项目启动时间
  2. 获取监听器,调用starting()逐个启动
  3. prepareEnvironment(listeners, applicationArguments);根据配置文件准备环境
  4. 打印banner
    5.创建并初始化ConfigurableApplicationContext
  5. 刷新上下文,调用注解,refreshContext(context);
  6. 创建tomcat并加载springmvc
  7. 刷新后的方法,空方法,给用户自定义重写afterRefresh()
  8. stopWatch.stop();结束计时
  9. 使用广播和回调机制告诉监听者springboot容器已经启动化成功,listeners.started(context);
  10. 使用广播和回调机制告诉监听者springboot容器已经启动化成功, listeners.running(context);
  11. 返回上下文

DNS(域名系统)是什么

DNS域名系统是将域名和IP相互映射的分布式数据库服务,可以通过域名查到对应的IP,让用户可以更好的记住地址

http超文本传输协议是什么

http超文本传输协议是运行在tcp之上的一种协议,基于请求响应模型的无状态协议,规定了一次请求和一次响应的格式

主从不一致怎么处理

  1. 对于业务量不大的场景,可以stop从库,切换到主库,然后同步数据
  2. 业务量大的话,可以找一个有效的从机,进行差异同步,

判断mysql中索引是否生效

使用explain关键字,语法是explain select * from t where ...
返回结果如下图
image
如果possible_keys行和key行都包含了某个索引,则说明在查询时使用了该索引。

  • possible_keys列给出了MySQL在搜索数据记录时可选用的各个索引。
  • key列是MySQL实际选用的索引。

Sql列转行

  • A.使用max(case when)
    SELECT name as '姓名',
    MAX(CASE WHEN course = '语文' THEN score END) AS '语文',
    MAX(CASE WHEN course = '数学' THEN score END) AS '数学',
    MAX(CASE WHEN course = '英语' THEN score END) AS '英语',
    MAX(CASE WHEN course = '历史' THEN score END) AS '历史'
    FROM t_student
    GROUP BY name;
  • B.使用sum(if(条件,列,为空替换值))
    SELECT name as '姓名',
    SUM(IF(course = '语文',score,0)) AS '语文',
    SUM(IF(course = '数学',score,0)) AS '数学',
    SUM(IF(course = '英语',score,0)) AS '英语',
    SUM(IF(course = '历史',score,0)) AS '历史'
    FROM t_student
    GROUP BY name;

数据库事务

  1. 事务的特点
    原子性:事务是一个逻辑单位,处于同一事务的操作要么都成功,要么都失败
    一致性:执行结果必须是从一个正确的状态变成另外一个正确的状态,实现一种可以预期的结果。
    隔离性:事务之间是独立的,不能相互影响
    持续性:事务一旦提交,对数据库的状态改变是永久的,后续的操作对其执行结果不应该有影响。
  2. 事务的隔离级别
    读未提交:事务可以读取别的事务没有提交的数据,可能出现脏读
    读已提交:事务只能读取别的事务已经提交的数据,可能出现幻读、不可重复度等情况
    可重复读:mysql默认的隔离级别,事务开启后不允许别的事务对数据进行update
    序列化读:数据库最高隔离级别,事务只能一个个排队执行,效率差
  3. 分布式事务的解决方案
    可以加全局锁,保证即时性比较高的业务,也可以通过消息机制进行事务补偿,保证最终一致性
  4. 声明式事务失效情况
    数据库不支持事务
    非public方法
    类内部方法调用
    异常使用try...catch...捕捉

什么是数据库回表操作

非主键索引树上存储的是索引值和与其对应的主键值,通过非主键索引查询会先在非主键索引树上查询出主键值,然后再到主键索引树上查询完整的记录,这个过程叫做回表;
若查询的结果在非主键索引树上都有则直接返回结果,不会进行回表。例如:select id from table where index=’i’

什么是索引下推

Mysql5.6版本有索引下推
将部分服务层负责的事情交给存擎处层理,减少回表操作。
索引规则是最左匹配原则
5.6之前:
存储引擎读取索引记录,联合索引使用最左匹配原则筛选一次,获取主键值
根据主键值定位完整记录(回表)
将记录返给server层进行条件筛选
5.6之后:
存储引擎读取索引记录,
判断条件部分能否使用索引列检查,否则处理下一个索引记录,是则定位完整记录
将记录返给server层进行条件筛选

索引失效的情况

1.不满足最左匹配原则
2.使用select *
3.在索引列上计算或者使用函数
4.字段类型不同,例如varchar类型的数字字符串在查询的时候写成了纯数字,但是int类型使用数字字符串传参却可以走索引,是因为mysql发现如果是int类型字段为查询条件,就会默认将字符串转换为int
5.模糊查询 %在最左边 例如 like ‘%xxx’
6.将记录的列对比时,索引也会失效
7.使用or关键字
8.非主键索引使用 not in会失效
9.使用not exists

where,group by,order by和having

1.where语句不能使用聚合函数,并且在group by 前面使用,having可以使用聚合函数,在group by 后面使用;where效率高于having
2.执行顺序时 where, group by, having, order by

常用的聚合函数

COUNT(*)——统计元组个数。
COUNT([DISTINCT|ALL]<列名>)——统计一列中值的个数。
SUM([DISTINCT|ALL]<列名>)——计算一列值的总和(此列必须是数值类型)。
AVG([DISTINCT|ALL]<列名>)——计算一列的平均值(同上)。
MAX([DISTINCT|ALL]<列名>)——求一列值中的最大值。
MIN([DISTINCT|ALL]<列名>)——求一列值中的最小值。

redis数据类型

string:字符串基本数据类型,每个value最多存储512M
list:集合
set:元素不可重复集合
zset:与set一样都是元素不可重复,但是关联了一个评分score,根据score升序排序
hash:键值对集合

redis持久化

Redis支持RDB(快照)和AOF(指令追加)两种方式持久化

  • RDB:在Redis.conf中默认使用RDB持久化机制,生产dump.rdb二进制文件
    save 900 1
    save 300 10
    save 60 10000
    以上配置标识900s内至少1个key的值变更,则持久化一次
    300s内至少10个key的值变更,持久化一次
    ......
  • AOF:redis.conf中默认关闭,开启方法是将如下配置的no改成yes
    appendonly no
    appendfilename "appendonly.aof" #指定文件名,不可更改
    AOF开启后将生成appendonly.aof文件,该文件记录了redis所有操作指令,当文件体积达到一定程度后将触发重写机制
    AOF有三种同步策略配置如下
    appendfsync always 每个指令同步一次,执行速度慢
    appendfsync everysec 每秒同步一次,最差只丢失1S内数据(推荐)
    appendfsync no 从不同步,不安全

redis主从模式和哨兵模式

1.主从模式解决的问题
应对频繁的读操作,实现读写分离,提高性能
提高服务的安全性,和健壮性,从服务作为主服务的灾备
2.哨兵模式解决的问题
在主从的基础上,增加哨兵监控,实现主从自动切换,避免了人工干预
原理:一般需要奇数个节点,哨兵不存储数据,会想主从机器发送ping命令监控服务状态。若某个哨兵发现主服务宕机,则该哨兵会进行主管线下,直到其他哨兵发现问题后投票进行客观下线,并选出设置优先级数量小(0除外)的从机切换为主机

redis分布式锁

获取锁失败后有三种处理方式
1.循环:可以结合程序内循环加队列的方式处理,现在程序内根据程序需要定义循环次数,都失败后放到等待队列中,避免业务中断
2.丢弃:根据业务需要,判断丢弃后是否有影响
3.阻塞:需要注意避免造成死锁

spring mvc参数传递

  • 不使用注解
    image
    url:支持
    form:支持
    json:不支持,但不报错
  • @RequestParam注解,只能修饰单一参数
    image
    url:支持
    form:支持
    json:不支持,报错 '' is not present
  • @PathVariable注解,将参数作为地址的一部分
    image
  • @RequestBody注解,只适合json格式数据传参
    image
    url:不支持
    form:不支持
    json:支持

springboot自动配置原理

image

image
启动类上注解@SpringBootApplication的修饰注解中有@EnableAutoConfiguration,这个注解中使用@Import注解加载了AutoConfigurationImportSelector,主要实现方法为getCandidateConfigurations,该方法被selectImports()调用,启动时在run方法的refreshContext方法中调用,目的是从jar包的META-INF/spring.factories中获取配置类集合

线程池任务调度流程

1.任务提交到线程池
2.判断是否达到核心线程数,未达到则新建一条线程执行任务
3.达到核心线程数,判断阻塞队列是否满了,未满则放入阻塞队列,等待工作线程执行完后从队列的开头获取任务执行
4.队列满了,判断是否达到最大线程树,未达到则新建一个非核心线程立即执行任务
5.达到最大线程数,执行拒绝策略

线程池核心参数

  • corePoolSize: 核心线程数,线程池维护最小线程数量,受到allowCoreThreadTimeOut配置影响
  • maxinumPoolSize:最大线程数,线程池可维护的最大线程数量,非核心线程受到keepAliveTime配置影响
  • keepAliveTime:非核心空闲线程最大存活时间,达到该设置值后会自动销毁
  • ThreadFactory: 线程工厂,创建线程并设置线程属性,比如线程名称,是否守护线程等
  • workQueue: 任务队列
    ArrayBlockingQueue: 有界数组阻塞队列,必须初始化大小
    LinkedBlockingQueue:无界链表阻塞队列,不用初始化大小
    SynchronousQueue: 无缓存阻塞队列;不会保存提交的任务,会一直创建新线程执行任务,触发最大线程数就执行拒绝策略
    PriorityBlockingQueue:无界有优先级阻塞队列;优先级通过参数Comparator实现
    DelayQueue:无界延迟阻塞队列;底层通过PriorityBlockingQueue实现,等任务达到过期时间,才会出队
  • rejectedExecutionHandler:拒绝策略;队列满了,并且触发最大线程数时执行
    AbortPolicy:丢弃任务并抛出RejectedExecutionException异常
    DiscardPolicy:丢弃任务但是不跑出异常
    DiscardOldestPolicy:丢弃任务队列最早的任务,把当前任务放入队尾
    CallerRunsPolicy:由提交任务的线程处理该任务,若线程池已shutdown则直接丢弃

mybatis中如何避免SQL注入

在mybatis中使用#{}的方式替代${}的方式接收参数,可以避免SQL注入,因为#{}使用的是预编译,会先替换为“?”然后再set值,而${}是字符串替换,在处理时是直接替换为变量的值。

mybatis中mapper的工作原理,参数不同时方法能不能重载

Dao也就是mapper接口,接口的权限定名,关联mybatis的namespace,然后接口中的方法名称与xml中的id映射。调用接口方法时,全限定名+方法名拼接为一个key,定位一个唯一的MapperStatement,在xml中每个sql标签会被解析成一个MapperStatement对象。

mapper中的方法不能重载,根据上述所说,每个MapperStatement的定义是全限定名+方法名拼接的key

mybatis分页原理,分页插件原理

Mybatis 使用 RowBounds 对象进行分页,它是针对 ResultSet 结果集执行的内存分页,而非物理分页。可以在 sql 内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页。

分页插件的基本原理是使用 Mybatis 提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的 sql,然后重写 sql,根据 dialect 方言,添加对应的物理分页语句和物理分页参数。

mybatis将结果集转成目标对象的映射方式

  • 使用标签将字段和对象属性对应
  • 使用sql别名,与对象属性对应

mybatis的缓存机制

mybatis的一级缓存和二级缓存默认都是基于PerpetualCache 的 HashMap 本地缓存,不同的是一级缓存默认开启,并且是session级别的,当session关闭后所有的cache都会清空,而二级缓存是namespaces级别的默认关闭,且可以自定义存储源,若开启二级缓存,使用到的类需要实现Serializable 序列化接口

对于缓存数据更新机制,当某一个作用域(一级缓存 Session/二级缓存Namespaces)的进行了 C/U/D 操作后,默认该作用域下所有 select 中的缓存将被 clear