某公司秋招技术一面题目分享
问题
一、并发与并行的区别
- 并发针对单核 CPU 而言,它指的是 CPU 交替执行不同任务的能力;看起来同一时间段在同时执行多个任务。
- 并行针对多核 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实现延迟队列,还能使用什么方式
- 基于RabbitMQ的死信队列
- 基于RabbitMQ的延迟队列插件
- Java自带的DelayQueue
- Redis的ZSet
- Redis的发布订阅
- 基于时间轮
四、jvm回收对象的方式,怎么确定一个对象是否要被回收
- 引用计数法:当该对象被其它对象引用的时候,引用计数器加一,当引用失效时,引用计数器减一;当为0时,就代表这个对象可以被回收;但这有个很大的缺陷,向两个对象发生相互引用时,就无法使引用计数器减一,也就无法回收该对象。
- 可达性分析法:通过一系列称为GCRoots的对象为起点,从这些节点向下搜索,节点走过的路径称为引用链,当一个对象到GCRoots没有任何引用链相连的话,证明此对象不可达,需要被回收。
五、Java枚举中的一个值、在其它方法中对其进行更改,最后获取出来的结果是否发生更改
个人测试,可以修改,因为枚举也有getter与setter方法,但是不建议更改,因为枚举本来就是作为常量使用的。
六、MySQL的索引数据结构,它们之间有什么区别
- B树&B+树(多路平衡二叉树):B 树的所有节点既存放键(key) 也存放 数据(data),而 B+树只有叶子节点存放 key 和 data,其它非叶子节点只存放 key。
- Hash:Hash索引,与HashMap的存储原理类似。
两者区别:Hash索引的查询速度比B+树更快,只需要一次Hash便可以找到键值,进而找到值;B+树需要从根节点遍历到叶子节点才能找到值。Hash不支持模糊查询,只能基础的比较查询。Hash索引不支持联合索引查询,且因为存在Hash碰撞的缘故,Hash索引没有B+树索引稳定。
七、MySQL的事务隔离级别
从低到高,并解决了什么问题:
- 读未提交:未解决任何问题,可能造成脏读、不可重复读、幻读。
- 读已提交:解决了脏读问题。
- 可重复读:解决了不可重复读问题。
- 序列化/串行化:解决了所有问题,表锁
MySQL默认隔离级别为可重复读。
注:MySQL的默认隔离级别可以解决幻读问题:
- 使用MVCC机制来保存不出现幻读。
- 使用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为例:
- 导出cpu或内存占用率(保存10次,24332为pid)(top命令)
top -b -n10 -p 24332 >> java_temp/topA.log
- 导出GC信息
jstat -gc 24332 >> java_temp/gc.log
- 导出栈空间日志
jstack 24332 >> java_temp/stack.log
- 导出堆空间日志
# 导出
jmap -dump:live,format=b,file=java_temp/heap.hprof 24332
# 开启,访问ip:9999
jhat -port 9999 java_temp/heap.hprof
十一、Linux确定Java进程的几种方式
- ps aux|grep java
- jps -l
十二、Spring获取配置文件值的几种方式
Spring加载配置文件的几种方式:
- FileSystemXmlApplicationContext:从xml文件中获取已定义的bean,需要给构造器完整的xml路径。
- ClassPathXmlApplicationContext:从xml文件中获取已定义的bean,需要给构造器相对的xml路径,容器从classpath路径寻找。
- WebXmlApplicationContext:容器从web应用程序范围内加载xml。
Spring读取配置文件的值
- @Value注解,读取比较简单的信息;例如:@Value(“${name}”),读取配置文件中键值为name的值。
- @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:
- 以MySQL为例,使用原生的在SQL语句后面拼接limit关键字。
- 继承MyBatis的Interceptor 类,重写里面的intercept方法,拦截要执行分页的sql语句,拼接limit关键字。
- 使用PageHelper插件进行分页,底层原理也是使用了mybatis的Interceptor
Interceptor 的底层原理使用了JDK的动态代理。
MyBatis-Plus:
- 除了使用以上MyBatis的方式外。
- 在MyBatis-Plus的配置文件中开始PaginationInnerInterceptor配置,对要分页的方法构造Page对象并传入方法中。
- 整个流程:先构造Page对象传入,获取原生SQL,有Page对象进行分页,获取总条数count,利用获取到的count进行分页。
个人猜测PaginationInnerInterceptor的底层原理使用的是动态代理。
我使用的MyBatis的PaginationInnerInterceptor。
十五、MyBatis中$与#的区别
${}是 Properties 文件中的变量占位符,它可以用于标签属性值和 sql 内部,属于静态文本替换。
#{}是sql的参数占位符,MyBatis 会将 sql 中的#{}替换为? 号,在 sql 执行前会使用 PreparedStatement 的参数设置方法,按序给 sql 的? 号占位符设置参数值。
十六、当有多个值时,MyBatis如何接收多个参数
- 将多个参数转成Map
- 使用JavaBean的方式
- 使用@Param注解标注参数名称
- 以上混合使用
十七、@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:
- 普通的使用SQL的字段重命名方式。
- 使用Mybaits的ResultMap进行字段与属性映射。
MyBatis-Plus:
除了使用Mybatis的方式外,还有以下方式:
使用@TableFiled注解,在JavaBean属性上标注字段名称。
## 外加今天
Redis如何存储点赞数,并排序
使用Redis的ZSet数据结构,键为赞的id,值为赞的数量,当获取热门点赞数据时,进行ZSet按点赞数的倒序排序。
开启定时任务,每隔多长时间,将点赞数持久化到数据库。





