2019年再深圳前半年就找了两次工作,前后大概面试了几十家,3月份面试总结部分丢失了,为了避免再丢失,将七月份的面试总结上传到网络上同时也分享给大家;
1.nginx的session共享:
复制session信息:
有几个tomcat,就复制几个session,只要有一个tomcat中的session发生变化,其他tomcat中的session跟着复制变化
sever.xml文件:将Cluster的注释去掉 :<Cluster className="org.apache.cataline.tcp.SimpleTcpCluster"/>
项目的web.xml:<distributable/>
ip绑定:第一次访问哪个tomcat,之后所有的请求都会被分配到那个tomcat上
修改一下nginx的配置文件即可
tomcat-redis-session-manager:
https://github.com/mzd123/session_manager下载解压
解压之后。将jar包放入tomcat的lib中
配置解压之后的redis-data-cache.properties......
使用jwt:放弃session机制,使用jwt机制,userid+随机数+签名加密生成一个token
2.io流:
字符流和字节流。字节流继承inputStream和OutputStream,字符流继承自InputSteamReader和OutputStreamWriter。
3.父子类的输出顺序:父类静态代码块–>子类静态代码块–>父类代码块–>父类构造–>子类代码块–>子类构造
(同样的是先执行静态代码块,并且只打印一次,此后都以父类代码块–>父类构造–>子类代码块–>子类构造顺序执行)
4.非关系型数据库:redis;Hbase;MongodDB;Neo4j;NewSQL
5.ssm流程:
① 客户端的所有请求都交给前端控制器DispatcherServlet来处理,它会负责调用系统的其他模块来真正处理用户的请求。
② DispatcherServlet收到请求后,将根据请求的信息(包括URL、HTTP协议方法、请求头、请求参数、Cookie等)以及HandlerMapping的配置找到处理该请求的Handler(任何一个对象都可以作为请求的Handler)。
③在这个地方Spring会通过HandlerAdapter对该处理器进行封装。
④ HandlerAdapter是一个适配器,它用统一的接口对各种Handler中的方法进行调用。
⑤ Handler完成对用户请求的处理后,会返回一个ModelAndView对象给DispatcherServlet,ModelAndView顾名思义,包含了数据模型以及相应的视图的信息。
⑥ ModelAndView的视图是逻辑视图,DispatcherServlet还要借助ViewResolver完成从逻辑视图到真实视图对象的解析工作。
⑦ 当得到真正的视图对象后,DispatcherServlet会利用视图对象对模型数据进行渲染。
⑧ 客户端得到响应,可能是一个普通的HTML页面,也可以是XML或JSON字符串,还可以是一张图片或者一个PDF文件。
6.redis数据不一致问题:
1、采用延时双删策略:在写库前后都进行redis.del(key)操作,并且设定合理的超时时间;public void write(String key,Object data){ redis.delKey(key); db.updateData(data); Thread.sleep(500); redis.delKey(key); }
步骤:1)先删除缓存
2)再写数据库
3)休眠500毫秒
4)再次删除缓存
2、异步更新缓存(基于订阅binlog的同步机制):
1、MySQL binlog增量订阅消费+消息队列+增量数据更新到redis
1)读Redis:热数据基本都在Redis
2)写MySQL:增删改都是操作MySQL
3)更新Redis数据:MySQ的数据操作binlog,来更新到Redis
2、Redis更新
1)数据操作主要分为两大块:
一个是全量(将全部数据一次写入到redis)
一个是增量(实时更新)
这里说的是增量,指的是mysql的update、insert、delate变更数据。
2)读取binlog后分析 ,利用消息队列,推送更新各台的redis缓存数据。
7.sql优化:
1.对查询进行优化,要尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建
立索引。
2.尽量避免在 where 子句中对字段进行 null 值判断
3.应尽量避免在 where 子句中使用 != 或 <> 操作符
4,尽量避免在 where 子句中使用 or 来连接条件,如果一个字段有索引,一个字段没有索
引,将导致引擎放弃使用索引而进行全表扫描
5.in 和 not in 也要慎用,否则会导致全表扫描
6.如果在 where 子句中使用参数,也会导致全表扫描
8.高并发:
(1)客户端层:典型调用方是浏览器browser或者手机应用APP
(2)反向代理层:系统入口,反向代理
(3)站点应用层:实现核心应用逻辑,返回html或者json
(4)服务层:如果实现了服务化,就有这一层
(5)数据-缓存层:缓存加速访问存储
(6)数据-数据库层:数据库固化数据存储
反向代理层的水平扩展,是通过“DNS轮询”;
站点层的水平扩展,是通过“nginx”实现的
服务层的水平扩展,是通过“服务连接池”实现的
在数据量很大的情况下,数据层(缓存,数据库)涉及数据的水平扩展,将原本存储在一台服务器上的数据(缓存,数据库)水平拆分到不同服务器上去
9.spring boot的启动原理:
1、spring boot应用打包之后,生成一个fat jar,里面包含了应用依赖的jar包,还有Spring boot loader相关的类
2、Fat jar的启动Main函数是JarLauncher,它负责创建一个LaunchedURLClassLoader来加载/lib下面的jar,并以一个新线程启动应用的Main函数。
10.Thread类:
创建(new)、就绪(runnable)、运行(running)、阻塞(blocked)、time waiting、waiting、消亡(dead)。
start方法启动;在run方法中定义具体要执行的任务;sleep相当于让线程睡眠;yield()方法将该线程转入到就绪状态;join方法,则等待thread执行完毕,如果调用的是指定了时间参数的join方法,则等待一定的事件。
interrupt中断一个正处于阻塞状态的线程;interrupted()函数是Thread静态方法,用来检测当前线程的interrupt状态
11.重载和重写:
一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同或者二者都不同)则视为重载;
子类与父类之间,重写要求子类被重写方法与父类被重写方法有相同的返回类型,比父类被重写方法更好访问,不能比父类被重写方法声明更多的异常
12.冒泡排序:
int arr[]={1,3,4,2};
int temp=0;
for(int i=0;i<arr.length-1;i++){
for(int j=0;j>arr.length-1-i,j++){
if(arr[j]>arr[j+1]){
temp=arr[j];
arr[j]=arr[j+1];
list[j+1]=temp;
}
}
}
13.cookie和session用法和区别:
cookie:存储于客户端(浏览器)。由于是保存在客户端上的,所以存在安全问题,并且cookie是由个数和大小限制的(4KB)
session:跟Cookie不同的是session是将数据存储在服务端的
14.堆,栈,静态代码块:
答:通常我们定义一个基本数据类型的变量,一个对象的引用,还有就是函数调用的现场保存都使用内存中的栈空间;
而通过new关键字和构造器创建的对象放在堆空间;
程序中的字面量(literal)如直接书写的100、”hello”和常量都是放在静态区中。
栈空间操作起来最快但是栈很小,通常大量的对象都是放在堆空间,理论上整个内存没有被其他进程使用的空间甚至硬盘上的虚拟内存都可以被当成堆空间来使用。
15.多线程实现方式,线程同步和锁机制
16.jsp的内置对象:
JSP有9个内置对象:
- request:封装客户端的请求,其中包含来自GET或POST请求的参数;
- response:封装服务器对客户端的响应;
- pageContext:通过该对象可以获取其他对象;
- session:封装用户会话的对象;
- application:封装服务器运行环境的对象;
- out:输出服务器响应的输出流对象;
- config:Web应用的配置对象;
- page:JSP页面本身(相当于Java程序中的this);
- exception:封装页面抛出异常的对象。
17.JSP和Servlet是什么关系:
JSP本质上是Servlet的一种简易形式,JSP会被服务器处理成一个类似于Servlet的Java程序,可以简化页面内容的生成。Servlet和JSP最主要的不同点在于,Servlet的应用逻辑是在Java文件中,并且完全从表示层中的HTML分离开来。而JSP的情况是Java和HTML可以组合成一个扩展名为.jsp的文件
JSP侧重于视图,Servlet更侧重于控制逻辑,在MVC架构模式中,JSP适合充当视图(view)而Servlet适合充当控制器(controller)
18.String和StringBuilder、StringBuffer的区别:
它们可以储存和操作字符串。其中String是只读字符串,也就意味着String引用的字符串内容是不能被改变的。
而StringBuffer/StringBuilder类表示的字符串对象可以直接进行修改,StringBuffer是线程安全的,Stringbuilder是非线程安全的
19.抽象类(abstract class)和接口(interface)异同
抽象类和接口都不能够实例化,但可以定义抽象类和接口类型的引用;
抽象类中的成员可以是private、默认、protected、public的,而接口中的成员全都是public的
20.用Java写一个单例类。
- 饿汉式单例
public class Singleton {
private Singleton(){}
private static Singleton instance = new Singleton();
public static Singleton getInstance(){
return instance;
}
}
懒汉式单例
public class Singleton {
private static Singleton instance = null;
private Singleton() {}
public static synchronized Singleton getInstance(){
if (instance == null) instance = new Singleton();
return instance;
}
}
21.sql行列互换:
select 年,
sum(case when 季度=1 then 销售量 else 0 end) as 一季度,
sum(case when 季度=2 then 销售量 else 0 end) as 二季度,
sum(case when 季度=3 then 销售量 else 0 end) as 三季度,
sum(case when 季度=4 then 销售量 else 0 end) as 四季度
from sales group by 年;
22.get和post请求的区别?
①get请求用来从服务器上获得资源,而post是用来向服务器提交数据;
②get将表单中数据按照name=value的形式,添加到action 所指向的URL 后面,并且两者使用"?"连接,而各个变量之间使用"&"连接;post是将表单中的数据放在HTTP协议的请求头或消息体中,传递到action所指向URL;
③get传输的数据要受到URL长度限制(1024字节);而post可以传输大量的数据,上传文件通常要使用post方式;
④使用get时参数会显示在地址栏上,如果这些数据不是敏感数据,那么可以使用get;对于敏感数据还是应用使用post;
23.MyBatis中使用#和$书写占位符有什么区别?
#将传入的数据都当成一个字符串,会对传入的数据自动加上引号;$将传入的数据直接显示生成在SQL中。
注意:使用$占位符可能会导致SQL注射攻击,能用#的地方就不要使用$,写order by子句的时候应该用$而不是#