问题

一、并发与并行的区别

  1. 并发针对单核 CPU 而言,它指的是 CPU 交替执行不同任务的能力;看起来同一时间段在同时执行多个任务。
  2. 并行针对多核 CPU 而言,它指的是多个 CPU核心或多个 CPU 在同一时刻同时执行多个任务。

二、Http属于哪一层

OSI七层网络模型 TCP/IP四层协议 对应网络协议
应用层(application) 应用层 HTTP、TFTP、FTP、SMTP
表示层(presentation) Telent、SNMP
会话层(session) SMTP、DNS
传输层(transport) 传输层 TCP、UDP
网络层(network) 网络层 IP、ICMP、ARP
数据链路层(data link) 数据链路层 FDDI、Ethernet、SLIP、PPP
物理层(physical) IEEE 802.1A IEEE 802.2 到IEEE 802.11

三、除了使用RabbitMQ实现延迟队列,还能使用什么方式

  1. 基于RabbitMQ的死信队列
  2. 基于RabbitMQ的延迟队列插件
  3. Java自带的DelayQueue
  4. Redis的ZSet
  5. Redis的发布订阅
  6. 基于时间轮

四、jvm回收对象的方式,怎么确定一个对象是否要被回收

  1. 引用计数法:当该对象被其它对象引用的时候,引用计数器加一,当引用失效时,引用计数器减一;当为0时,就代表这个对象可以被回收;但这有个很大的缺陷,向两个对象发生相互引用时,就无法使引用计数器减一,也就无法回收该对象。
  2. 可达性分析法:通过一系列称为GCRoots的对象为起点,从这些节点向下搜索,节点走过的路径称为引用链,当一个对象到GCRoots没有任何引用链相连的话,证明此对象不可达,需要被回收。

五、Java枚举中的一个值、在其它方法中对其进行更改,最后获取出来的结果是否发生更改

个人测试,可以修改,因为枚举也有getter与setter方法,但是不建议更改,因为枚举本来就是作为常量使用的。

六、MySQL的索引数据结构,它们之间有什么区别

  1. B树&B+树(多路平衡二叉树):B 树的所有节点既存放键(key) 也存放 数据(data),而 B+树只有叶子节点存放 key 和 data,其它非叶子节点只存放 key。
  2. Hash:Hash索引,与HashMap的存储原理类似。

两者区别:Hash索引的查询速度比B+树更快,只需要一次Hash便可以找到键值,进而找到值;B+树需要从根节点遍历到叶子节点才能找到值。Hash不支持模糊查询,只能基础的比较查询。Hash索引不支持联合索引查询,且因为存在Hash碰撞的缘故,Hash索引没有B+树索引稳定。

七、MySQL的事务隔离级别

从低到高,并解决了什么问题:

  1. 读未提交:未解决任何问题,可能造成脏读、不可重复读、幻读。
  2. 读已提交:解决了脏读问题。
  3. 可重复读:解决了不可重复读问题。
  4. 序列化/串行化:解决了所有问题,表锁

MySQL默认隔离级别为可重复读。

注:MySQL的默认隔离级别可以解决幻读问题:

  1. 使用MVCC机制来保存不出现幻读。
  2. 使用Next-Key Lock(行锁)+ Gap Lock(间隙锁)结合,行锁锁住当前行,避免插入新行,还需间隙锁。

八、MySQL的MVCC指的是什么

指的是:多版本并发控制,指的就是在使用read-committed、repeatable-read这两种隔离级别的事务,在执行普通的 SELECT 操作时,访问记录的版本链的过程。

这样子可以使不同事务的读-写、写-读操作并发执行,从而提升系统性能。

read-committed、repeatable-read 这两个隔离级别的一个很大不同就是:生成ReadView 的时机不同

read-committed 在每一次进行普通 select 操作前都会生成一个 ReadView,而repeatable-read 只在第一次进行普通 select 操作前生成一个 ReadView,之后的查询操作都重复使用这个 ReadView 就好了。

九、MySQL如何确定一条SQL语句执行快慢

使用MySQL的explain命令,在要查询的SQL语句前加上explain,查询出这条SQL语句的执行计划信息。如果进行了连表查询,这个分别输出每一张表的执行计划。例如:

mysql> explain select * from actor;

id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE actor ALL NULL NULL NULL NULL 2 NULL

id:表示执行的表的顺序,id越大,优先级越高,越先执行

select_type:simple:简单查询,不包含子查询与联合查询;subquery:包含在select中的子查询;primary:复杂查询的外层查询;derived:包含在from查询中的子查询,MySQL会将结果存放在一个临时表中,也称为派生表;union:在union后面的查询;union result:从union临时表中检索结果的查询。

table:这一列表示 explain 的一行正在访问哪个表。当 from 子句中有子查询时,table列是 格式,表示当前查询依赖 id=N 的查询,于是先执行 id=N 的查询。当有 union 时,UNION RESULT 的 table 列的值为 <union1,2>,1和2表示参与 union 的 select 行id。

type:这一列表示关联类型或访问类型,即MySQL决定如何查找表中的行。依次从最优到最差分别为:system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL

**NULL**:mysql能够在优化阶段分解查询语句,在执行阶段用不着再访问表或索引。例如:在索引列中选取最小值,可以单独查找索引来完成,不需要在执行时访问表。

**const, system**:mysql能对查询的某部分进行优化并将其转化成一个常量(可以看show warnings 的结果)。用于 primary key 或 unique key 的所有列与常数比较时,所以表最多有一个匹配行,读取1次,速度比较快。

**eq_ref**:primary key 或 unique key 索引的所有部分被连接使用 ,最多只会返回一条符合条件的记录。这可能是在 const 之外最好的联接类型了,简单的 select 查询不会出现这种 type。

**ref**:相比 eq_ref,不使用唯一索引,而是使用普通索引或者唯一性索引的部分前缀,索引要和某个值相比较,可能会找到多个符合条件的行。

**ref_or_null**:类似ref,但是可以搜索值为NULL的行。

**index_merge**:表示使用了索引合并的优化方法,既用到了主键索引,又用到了普通索引。

**range**:范围扫描通常出现在 in(), between ,> ,<, >= 等操作中。使用一个索引来检索给定范围的行。

**index**:和ALL一样,不同就是mysql只需扫描索引树,这通常比ALL快一些。

**ALL**:即全表扫描,意味着mysql需要从头到尾去查找所需要的行。通常情况下这需要增加索引来进行优化了

possible_keys:这一列显示查询可能使用哪些索引来查找。 explain 时可能出现 possible_keys 有列,而 key 显示 NULL 的情况,这种情况是因为表中数据不多,mysql认为索引对此查询帮助不大,选择了全表查询。 如果该列是NULL,则没有相关的索引。在这种情况下,可以通过检查 where 子句看是否可以创造一个适当的索引来提高查询性能,然后用 explain 查看效果。

key:这一列显示mysql实际采用哪个索引来优化对该表的访问。如果没有使用索引,则该列是 NULL。如果想强制mysql使用或忽视possible_keys列中的索引,在查询中使用 force index、ignore index。

key_len:这一列显示了mysql在索引里使用的字节数,通过这个值可以算出具体使用了索引中的哪些列。

key_len计算规则如下:

  • 字符串
    • char(n):n字节长度
    • varchar(n):2字节存储字符串长度,如果是utf-8,则长度 3n + 2
  • 数值类型
    • tinyint:1字节
    • smallint:2字节
    • int:4字节
    • bigint:8字节

      

  • 时间类型 
    • date:3字节
    • timestamp:4字节
    • datetime:8字节
  • 如果字段允许为 NULL,需要1字节记录是否为 NULL

索引最大长度是768字节,当字符串过长时,mysql会做一个类似左前缀索引的处理,将前半部分的字符提取出来做索引。

ref列:这一列显示了在key列记录的索引中,表查找值所用到的列或常量,常见的有:const(常量),func,NULL,字段名

rows:这一列是mysql估计要读取并检测的行数,注意这个不是结果集里的行数。

extra:这一列展示的是额外信息。常见的重要值如下:

distinct: 一旦mysql找到了与行相联合匹配的行,就不再搜索了。

**using index**:这发生在对表的请求列都是同一索引的部分的时候,返回的列数据只使用了索引中的信息,而没有再去访问表中的行记录。是性能高的表现。

**using where**:mysql服务器将在存储引擎检索行后再进行过滤。就是先读取整行数据,再按 where 条件进行检查,符合就留下,不符合就丢弃。

**using temporary**:mysql需要创建一张临时表来处理查询。出现这种情况一般是要进行优化的,首先是想到用索引来优化。

**using filesort**:mysql 会对结果使用一个外部索引排序,而不是按索引次序从表里读取行。此时mysql会根据联接类型浏览所有符合条件的记录,并保存排序关键字和行指针,然后排序关键字并按顺序检索行信息。这种情况下一般也是要考虑使用索引来优化的。

十、如何导出生产环境下的jvm堆栈信息

以下以Linux为例:

  1. 导出cpu或内存占用率(保存10次,24332为pid)(top命令)
top -b -n10 -p 24332 >> java_temp/topA.log
  1. 导出GC信息
jstat -gc 24332 >> java_temp/gc.log
  1. 导出栈空间日志
jstack 24332 >> java_temp/stack.log
  1. 导出堆空间日志
# 导出
jmap -dump:live,format=b,file=java_temp/heap.hprof 24332
# 开启,访问ip:9999
jhat -port 9999 java_temp/heap.hprof

十一、Linux确定Java进程的几种方式

  1. ps aux|grep java
  2. jps -l

十二、Spring获取配置文件值的几种方式

Spring加载配置文件的几种方式:

  1. FileSystemXmlApplicationContext:从xml文件中获取已定义的bean,需要给构造器完整的xml路径。
  2. ClassPathXmlApplicationContext:从xml文件中获取已定义的bean,需要给构造器相对的xml路径,容器从classpath路径寻找。
  3. WebXmlApplicationContext:容器从web应用程序范围内加载xml。

Spring读取配置文件的值

  1. @Value注解,读取比较简单的信息;例如:@Value(“${name}”),读取配置文件中键值为name的值。
  2. @ConfigurationProperties,读取同一父配置集合下所有的配置文件信息,将获取的数据与Bean实体绑定。

十三、SpringMVC如何获取客户端的ip,具体实现方式

以下展示多种实现方法

public String getIP(HttpServletRequest request){
String ip=request.getHeader("x-forwarded-for");
if(ip==null || ip.length()==0 || "unknown".equalsIgnoreCase(ip)){
ip=request.getHeader("Proxy-Client-IP");
}
if(ip==null || ip.length()==0 || "unknown".equalsIgnoreCase(ip)){
ip=request.getHeader("WL-Proxy-Client-IP");
}
if(ip==null || ip.length()==0 || "unknown".equalsIgnoreCase(ip)){
ip=request.getHeader("X-Real-IP");
}
if(ip==null || ip.length()==0 || "unknown".equalsIgnoreCase(ip)){
ip=request.getRemoteAddr();
}
return ip;
}

十四、MyBaits/MyBatis-Plus分页的实现原理,你是用什么方式实现的

MyBatis:

  1. 以MySQL为例,使用原生的在SQL语句后面拼接limit关键字。
  2. 继承MyBatis的Interceptor 类,重写里面的intercept方法,拦截要执行分页的sql语句,拼接limit关键字。
  3. 使用PageHelper插件进行分页,底层原理也是使用了mybatis的Interceptor

Interceptor 的底层原理使用了JDK的动态代理。

MyBatis-Plus:

  1. 除了使用以上MyBatis的方式外。
  2. 在MyBatis-Plus的配置文件中开始PaginationInnerInterceptor配置,对要分页的方法构造Page对象并传入方法中。
  3. 整个流程:先构造Page对象传入,获取原生SQL,有Page对象进行分页,获取总条数count,利用获取到的count进行分页。

个人猜测PaginationInnerInterceptor的底层原理使用的是动态代理。

我使用的MyBatis的PaginationInnerInterceptor。

十五、MyBatis中$与#的区别

${}是 Properties 文件中的变量占位符,它可以用于标签属性值和 sql 内部,属于静态文本替换。

#{}是sql的参数占位符,MyBatis 会将 sql 中的#{}替换为? 号,在 sql 执行前会使用 PreparedStatement 的参数设置方法,按序给 sql 的? 号占位符设置参数值。

十六、当有多个值时,MyBatis如何接收多个参数

  1. 将多个参数转成Map
  2. 使用JavaBean的方式
  3. 使用@Param注解标注参数名称
  4. 以上混合使用

十七、@RestController由哪几个注解构成

@Controller+@Reponsebody

ResonseBody将Controller的返回值直接返回到前端,如果是String,则直接返回,如果是对象,则转成Json字符串返回。

十八、值传递与引用传递的区别

值传递:在调用函数时,将实际的参数复制一份传递到函数中,这样在函数中进行修改,不影响原来的参数。

引用传递:在调用函数时,将实际参数的地址传递给函数,在函数中进行修改时,会影响到原来的值。

十九、MySQL删除一张表数据的方式

delete:删除表数据,可添加删除条件,一行一行删除,效率慢,不删除表结构,数据可以回滚。

drop:删除表中数据,连同表结构一同删除,不可回滚。

truncate:删除表中所有数据,不删除表结构,不可回滚。

二十、Redis数据如何防止丢失,你的实现方法是什么

持久化方式:Redis的两种数据持久化方式。

RDB:也称为Redis数据快照,以二进制方式保存Redis内存某一时刻的内存数据信息,又可以定时保存,如最近多少分钟内有多少条数据写入,达到条件自动写入。

优点:RDB文件比较小,Redis加载RDB文件比较快,能够在很短时间内恢复。

缺点:指的某一时刻的内存数据,系统发生宕机,数据丢失较多,RDB数据写入比较耗性能。

AOF:也称为日志追加,就是执行一条命令,写一条AOF日志,可以设置刷盘方式,比如每次写入命令就同步日志,或者一次同步一次。

优点:数据丢出程度较RDB少。

缺点:随着时间变成,AOF文件会越来越大,AOF刷盘影响性能。

AOF的持久化方式比RDB优先级更高。

主从复制

集群化

我是用的方式是单节点的数据持久化,使用的RDB数据快照的方式。

二十一、Http状态码300开头指什么,301和302有什么区别

300:代表重定向。

301:永久重定向,不保留上一页面内容,将上一页面用这个页面替换,爬虫也只保存此页面。

302:临时重定向,保留上一页页面的内容,浏览器缓存上一页面,爬虫也保留以页面。

二十二、类变量与实例变量的区别

类变量:通过类名访问,先于对象存在,随着类的加载而加载,被所有对象共享。

实例变量: 通过实例化的对象进行访问,对象私有,不被其它对象更改。

二十三、yml与properties有什么区别

yml:以:进行属性分割,拥有天然的树状结构,格数与json非常相似,对中文支持友好。

properties:以.进行分割,用=好进行赋值,对空间的利用率没有yml高,对中文不友好,优先级比yml高。

二十四、当Mybatis/MyBatis-Plus中JavaBean属性与表字段不一致时怎么办

MyBatis:

  1. 普通的使用SQL的字段重命名方式。
  2. 使用Mybaits的ResultMap进行字段与属性映射。

MyBatis-Plus:

除了使用Mybatis的方式外,还有以下方式:

使用@TableFiled注解,在JavaBean属性上标注字段名称。

## 外加今天

Redis如何存储点赞数,并排序

  1. 使用Redis的ZSet数据结构,键为赞的id,值为赞的数量,当获取热门点赞数据时,进行ZSet按点赞数的倒序排序。

  2. 开启定时任务,每隔多长时间,将点赞数持久化到数据库。