1.Java中基本数据类型有哪些?
基本类型: byte,short,int,long,float,double,char,boolean
包装类:Byte,Short,Integer,Long,Float,Double,Character,Boolean
2.Integer 和 int的区别
- int是基本数据类型,Integer 是引用数据类型
- int 的默认值是0,Integer的默认值是null
- int 类型可以直接存储值,Integer 需要 实例化对象,指向对象的地址。
3.String和StringBuilder和StringBuffer区别
他们都是字符串,但是String是一个对象,而不是可变数组,所以不能修改。
而StringBuilder和StringBuffer是可变数组,所以用来频繁操作字符串,然后StringBuilder对方法添加了synchronized,所以线程是安全的,但是效率慢,进行线程阻塞和唤醒的代价较高,而StringBuffer没有添加synchronized,所以线程不安全,但是效率高。
线程堵塞:就是在同一时间两个线程同时运行一段代码,而一个线程在另一个线程运行结束之前是不能获得cpu执行权的,这就是线程堵塞
处理方案:调用wait方法将cpu的执行权交给另一个线程
4.String a = “A” 和 String a = new String(“A”) 创建字符串的区别
String a = “A”是到常量池中寻找”A”,如果有就将地址传递给a,如果没有就创建一个”A”再把地址传给a,String a = new String(“A”) 是不管常量池中有没有”A”在内存中先创建一个”A”,然后再确保常量池中有一个内容相同的String对象
5.== 和 equals 的区别是什么
==比较的是两个对象的地址,而equals比较的是两个对象的内容是否相等
6.final 和 finally 和 finalize 的区别
final是表示一个类或者对象不允许被修改,finally是配合try/catch使用的,表示该语句最后一定会执行,finalize是一个方法,是在gc启动前,该对象被回收前调用的方法
7.JDK 和 JRE 有什么区别?
JDK是java的开发工具包,包含JRE,同时还包含了编译器,而JRE是java运行环境,包含了JVM
8.面向对象四大特性
抽象:就是抽取公共特征的代码的过程
封装:就是用权限修饰符将内容保护起来,只能通过某一个接口调用,权限修饰符分为public,所有地方都能调用,protected,只能在同包和子类,默认,只能在同包中调用,private,只能在本类调用
继承:分为子类父类,子类可以使用super调用父类中的变量,还可以重写父类的方法使方法更加具体化
多态:就是对象在编译时和运行时的类型不一样,比如Map map = new HashMap()
9.方法重写和重载
方法重写即将父类中的方法的实现过程具体化,其形参跟返回值都不能变,
方法重载是在同一个类中方法名相同,但是形参不同,返回值也可以不同
10.普通类和抽象类
普通类:不包含抽象方法,可以实例化
抽象类:必须包含抽象方法,不可以实例化,和被private,static,final修饰
11.接口和抽象类的区别
接口:没有构造器,由成员变量和抽象方法组成,jdk8以后有default方法和static方法,与类是实现关系
抽象类:有构造器,由抽象方法和普通方法组成,与类是继承关系
12.你知道BIO,NIO,AIO么?
(内核:内核就是用来连接硬件和应用层的桥梁,阻塞:当发起一个请求之后,必须要一直等到该请求操作完毕之后才能进行下一步,非阻塞:当发起请求之后不需要一直等待结果返回,可以先干其他事)
BIO:是同步阻塞模型,就是从发起io请求开始,不管内核有没有准备好,线程都一直堵塞,直到操作完成。
NIO:同步非阻塞模型,发起io请求后立马返回,当内核准备io完成之后,再通过调用callback方法通知线程做io操作,然后线程开始阻塞,直到操作完毕
AIO:异步非阻塞模型,发起io请求之后立即返回,内存做好io操作之后调用callback方法通知线程io操作的结果
13.java 中四大基础流
InputStream:输入字节流
OutputStream:输出字节流
Reader:输入字符流
Writer:输出字符流
14.读文本用什么流,读图片用什么流
文本用字符流,因为字符流操作的基本单元是Unicode,Unicode中包含了世界上所有的文字,图片用字节流,因为虽然他可以处理所有类型的数据,但是它不支持读写Unicode
16.BufferedInputStream 用到什么设计模式
适配器和装饰者模式
17.带缓冲区的流有哪些
BufferedInputStream:带缓冲区的字节输入流
BuffueredOutputSteam:带缓冲区的字节输出流
BufferedReader:带缓冲区的字符输入流
BufferedWriter:带缓冲区的字符输出流
18.说一下Java中的集合体系
Collection接口:
List:有序有重复集合
ArrayList:底层基于数组实现,查询效率高,增改效率低
Victor:就是一个线程安全的ArrayList,因为添加了同步锁,ArrayList会自动扩容0.5倍,Victor扩容1倍
LinkedList:基层基于双向链表,线程不安全,查询效率低,因为它不支持索引,但是增改效率高,它增删只需要改变指针指向
set:无序无重复集合,通过HashCode值和equals进行判断是否重复
HashSet:底层基于HashMap的Key保存元素,
TreeSet:有序不重复集合,底层是基于TreeMap的key保存元素,排序方式为自然排序
Map接口:
HashMap:key的值没有顺序,key和value都允许为null,且线程不安全
TreeMap:key的值自然排序,线程不安全
HashTable:key的值都不允许为null,线程安全,因为添加了synchronized,所以相比HashMap来说效率也低一点,然后我们一般不考虑线程安全问题的话就会使用HashMap
Properties:key和value都为String类型,线程安全,因为继承自HashTable
19.HashMap和HashTable的区别
20.ArrayList和LinkedList区别
21.ArrayList和Vector区别
22.一个User的List集合,如何实现根据年龄排序
第一种:实现Comparable,重写compareTo方法,在方法中自定义比较算法
第二种:调用Collections.sort方法,传入一个比较器,重写compare方法,在方法中定义比较算法
23.HashMap底层用到了那些数据结构?
JDK8以前是数组和链表,而从JDK8开始新增了红黑树
24.什么是Hash冲突
就是key拿着通过hash算法得到的地址去储存,结果该地址已被占用
解决方案:
拉链法:就是将key再指向另一个地址
开放寻址法:将产生冲突的值再次进行计算,直到不冲突为止
再散列法:换一种hash算法再计算一次
建立公共溢出区:将hash表分为基本表和溢出表,然后把冲突的值移到溢出表
25.HashMap为什么要用到链表结构
就是为了解决数据发生hash碰撞就会将原有的数组下标对应的值替换
26.HashMap为什么要用到红黑树
因为如果hashmap中同一个索引进行了多次碰撞的话,链表的长度就会越来越长,从而影响效率,所以jkd8以后新增了红黑树,链表长度大于8的时候自动转换为红黑树
27.HashMap链表和红黑树在什么情况下转换的?
当链表长度大于等于8的同时数组长度大于64,就会自动转换为红黑树,然后当红黑树节点小于6时转换为链表
28.HashMap在什么情况下扩容?HashMap如何扩容的?
hashmap数组的默认初始容量是16,然后负载因子默认为0.75,当数据长度达到160.75的时候就会成倍扩容
(为什么是0.75:因为负载因子太小的话浪费空间,太大又容易造成哈希碰撞,所以经过考虑采用了0.75,当然负载因子也可以自定义
为什么是成倍扩容:因为需要保证数组的长度是2的整数次幂
为什么长度必须是2的整数次幂:因为在转换为2进制之后都是1,在进行与运算之后就能确保取到当前数组最大范围之内的索引,并且不会越界
)
29.HashMap是如何Get一个元素的
首先进行Hash运算,计算出索引,然后判断该索引是否有数据,如果没有数据的话直接返回null,如果有值就查询该数据的key是否是查询的key,是的话就就返回该value,如果不是的话就判断是红黑树还是链表,是红黑树的话就按照红黑树的查询方式查询元素并返回,如果是链表就遍历匹配key,然后返回value
30.你知道HahsMap死循环问题吗
因为在HashMap扩容的时候会将数据放到一个新数组中,然后这个操作会导致数据颠倒,就比如a>b>null会变成b>a>null,这个过程单线程是没有问题的,但是在多线程中的话就可能会出现b>a>b>a,这就是死循环,然后用ConcurrentHashMap就可以解决这个问题
31.说一下你对ConcurrentHashMap的理解
JDK7:采用了分段锁思想,就是将hash表分为了多个segment字段,然后每个字段都用一把锁来锁住,这样就不会存在锁竞争
JDK8:进行了两点修改:
1.取消了segment字段,然后采用了CAS操作和Synchronized来实现(CAS:就是在修改一个变量的值的时候,只有预期原值跟地址中的值一样时才会修改)
32.HashMap是如何Put一个元素的
先通过hash算法求出当前索引,然后如果当前索引为空的话就直接插入到数组内,如果不为空的话就出现了hash冲突,需要判断新元素和旧元素是不是同一个key,是的话就覆盖,如果不是再判断是否是红黑树,如果是红黑树的话就按红黑树的方式写入数据,否则就遍历链表直到找到一个空节点插入数据,若当前链表长度不小于8时就转为红黑树再插入
33.平局值用什么,分组用什么
平均值:avg,分组:group by
34.两个相同列的结果集求并集用什么
并集是union,但是这是两个相同列的话就得用union all,union all允许重复并集
35.完整查询SQL中的关键字的定义顺序
select列名 from表名 join表名 on条件 where条件 group by列名 having列明 order by条件 limit列名
36.完整的多表JOIN查询,SQL中关键字的执行顺序
from on join where group by having order by limit
37.员工表employee字段有: id, username, amount ,deptname . 求每个部门总人数怎么做 ,
select count(id)from emp group by dept
38.求每个部门总工资怎么做?
select sum(amount)from emp group by dept
39.介绍一下Spring
spring是一个轻量级的容器框架,开发简单,功能强大,然后主要分为两个功能,第一个是IOC控制反转,就是将对象的管理权全权交予给spring进行管理,然后再通过依赖注入的方式获取对象以达到解耦,然后是AOP面向切面编程,就是将逻辑相同的代码抽取出来封装方便复用,就比如像日志管理跟事务管理,这两个业务如果不使用AOP的话就会产生大量的相同代码,但是一旦使用AOP的话代码就会大大减少,这也是解耦
40.说下Spring框架的组成
core核心模块:core,核心包;beans,bean包;context,提供国际化和事务;el:el表达式包
web模块:web,提供上下文;web-mvc:提供视图mvc,web-socket:通信方式
数据集成模块:JDBC,操作数据库;Transaction:事务管理
其他模块:AOP,面向切面编程;Aspect,AOP框架;Test,测试包
41.什么是Spirng的IOC
42.你对AOP的理解,实现原理是什么
底层基于动态代理
43.Spring的Bean懒加载和非懒加载有什么区别
懒加载就是再调用对象是再创建对象,节约资源,但是不方便排错,而非懒加载是在容器启动的时候就创建了对象,消耗资源但是方便排错
44.Spring的依赖注入方式有哪些
setter注入:通过反射无参构造器生成对象,支持注解和xml两种方式,注解主要就是@AutoWired
构造器注入:通过反射有参构造生成对象,同样也支持注解和xml两种注入方式
45.说一下定义切面相关的注解
@Aspect:定义切面
@Pointcut:定义切点
@Around:环绕通知
46.Spring中Bean的四种注册方式
普通工厂注册
静态工厂注册
实体工厂注册
FactoryBean注册
47.注册Bean的注解有哪些
@Controller,@Service,@Component,@Configuration
48.IOC的启动流程有了解过吗
分为两个阶段,容器启动阶段和Bean实例化阶段,容器启动阶段是读取配置和分析配置信息,然后Bean实例化阶段是实例化对象,装配依赖和生命周期回调等等
49.Bean的生命周期讲一下
实例化,属性注入,初始化,使用,销毁
50.单例多例的区别
单例:所有请求都只用一个对象来处理,因为比如像service而言,很多操作都是重复的,每次都生成一个对象的话就很浪费资源
多例:每次请求都生成一个新的对象来处理,为了防止并发问题,然后ioc中的bean默认模式都是单例,需要开启多例的话可以修改scope属性为prototype
51.Spring的Bean被指定为prototype以及singleton有什么区别
52.BeanFactory和ApplicationContext有什么区别
BeanFactory是Spring IOC的核心接口,用来管理Bean的,而ApplicationContext是BeanFactory的子接口,不仅继承了BeanFactory管理Bean的所有方法,还扩展了环境、国际化等接口
53.BeanFactory和FactoryBean的区别
BeanFactory是Spring IOC的核心接口,用来管理Bean的,FactoryBean只是Spring创建Bean的一种方式,
54.IOC容器是如何保证Bean的单例的?
IOC会将单例的bean放入一个ConcurrentHashMap中,因为ConcurrentHashMap是线程安全的,然后调用bean的时候会先到这个map中寻找,如果没有这个bean再创建新的
55.Spring如何解决Bean的循环依赖
循环注入的的话一共是分三种,构造器注入,setter注入和多例bean循环,然后Spring的话是依靠三级缓存(单例对象缓存)来解决了setter注入
解决步骤:
假设有A/B两个互相依赖的变量,在创建A时就会将A放到三级缓存singletonFactories中,然后此时需要B,就会去三级缓存中找B,如果没有就走B的创建流程,需要A的同时发现了在三级缓存中有A,就会调用getObject方法获取A,并放到二级缓存earlySingletonObjects中,再移除掉三级缓存中的A,此时B完成注入,就会放入一级缓存singletonObjects中,然后A从一级缓存中就可以获取B完成注入
56.Spring构造器注入允许循环依赖吗为什么
不能,因为如果使用构造器来构造提早暴露但是没有设置值bean的话就会产生无限递归创建
57.说几个Spring的IOC的容器工厂类
BeanFactory:ioc容器的顶级接口,提供了bean的获取方法
DefaultListableBeanFactory:Spring注册和加载bean的默认实现
ApplicationContext:BeanFactory的子类,额外提供了国际化和环境等操作
ClasspathXmlApplicationContext:从class path中获取xml配置
58.你知道Spring的AOP主要基于什么设计模式实现吗
动态代理,就是在运行时动态为原生类生成代理类,可以在代理类中调用原生类和增强业务,然后默认会选择cglib动态代理
cglib(支持没有接口的类);jdk(只支持有接口的类)
59.你知道@Autowaire自动注入的实现原理吗?
是通过BeanPostProcessor后置处理器实现的,在bean实例化过程中它会扫该类中是否有@Autowaired注解,然后得到自动注入依赖bean的类型,并去容器中得到依赖bean的实例,如果没有的话就会创建一个新的依赖bean然后通过反射赋值
60.你知道@Transcational注解的实现原理吗?
就是基于异常来的,但是如果该方法的内部捕捉了异常或者私有化了方法的话@Transactional就会失效
61.常见Http状态码
200 成功
300 重定向
401 没有访问权
403 禁止访问
405 方法不被允许
500 服务端错误62.Servlet的生命周期
实例化,初始化,处理请求,最后销毁
63.什么是过滤器?怎么创建一个过滤器
过滤器就是拦截接收的请求,然后可以对请求的参数进行处理
创建一个类,实现filter接口,重写doFilter方法,最后在web.xml中配置
64.讲一下Session的工作原理
就是后端生成一个session时候会将sessioId发送给前端,然后前端保存sessionId,之后的每次请求都携带sessionId,后端接收到sessionId之后就能查找到该session
65.Session和cookie有什么区别
session跟cookie最大的区别就是保存的位置,cookie是保存在浏览器,session在服务器,然后cookie应为是保存在浏览器的,所以不安全,而且只能操作字符串,大小还有限制,session的安全性就比cookie高很多,所有数据都能操作,还没有大小限制,但是保存多了之后服务器就会降低性能
66.说说preparedStatement和Statement的区别
preparedStatement继承自Statement,然后preparedStatement拼接sql语句使用的?作为占位符,防注入,而Statement不防注入,而且preparedStatement是预编译sql语句,所以效率也高
67.statement有sql注入风险,preparedStatement没有sql注入风险
因为statement是直接将参数写在sql语句内,而preparedStatement是使用了?作为占位符拼接sql
68.请求转发和重定向的区别
转发是一次请求,可以共享参数,而重定向则是多次请求,所以不能共享参数,然后转发是可以访问项目web-inf下的资源,不能访问外部的,重定向则可以访问外部资源,但是不能访问web-inf下的资源
69.get和post请求的区别
get的参数是保存在地址栏的,不安全,post是将参数保存在请求内的,所以安全性高,然后get还有大小限制,大概2kb,post没有限制
70.JSP的原理
jsp其实就是一个servlet,所以它也会经历servlet的生命周期,然后每个jsp文件都会被编译成一个servelet去执行,在该servelet中会对jsp内容中的动态内容进行替换
71.SpringMVC怎么样设定重定向和转发的
转发:forward
重定向:redirect
72.SpringMVC如何对时间格式的参数进行格式化
对前端传输的参数时间格式化使用@DateTimeFormat,然后对后端发送给前端的参数格式化使用@JsonFormat
72.SpringMVC常用的注解有哪些
@Controller,@RequesMapping,@RequestBody,@RestController
74.如何定义SpringMVC的拦截器
创建一个类实现HandlerInterceptor接口,然后重写preHandle方法,在方法中编写逻辑,然后在配置类中配置拦截、放行地址
75.HandlerInterceptor和HandlerInterceptorAdapter的区别
可以使用HandlerInterceptorAdapter来简化拦截器的实现
76.SpringMVC的执行原理
前端发送请求到后端,然后后端核心控制器DispatcherServlet接收到之后会将请求给HandlerMapping映射器进行映射,映射完毕之后再交给适配器HandlerAdaptor进行适配,适配完毕就会返回一个ModelAndView对象给视图解析器ViewResolver解析,解析完毕之后就会交给View响应给前端
77.SpringMVC的Controller是单例还是多例,有没有并发安全问题,如何解决
spring中的bean都是默认为单例模式的,而controller也是一个bean,所以也是单例的,而单例的话他就有并发安全问题,因为controller中的成员变量时是所有线程共有,而当一个线程带调用成员变量时,另一个线程抢先将其修改了的话,调用的时候就是修改过的值,最直接的解决方法就是不要在controller中定义成员变量,如果非要定义的话可以给controller加上@Scope(“portotype”)属性
78.RequestMapping 和 GetMapping有什么区别
RequestMapping 可以接收所有的请求,而GetMapping只能接收get请求
79.相比Spring,Spring Boot有哪些优点
SpringBoot是基于Spring实现的框架,然后对Spring进行了大量的简化,比如整合了很多第三方框架,像redis,mybaits等,还有像基于注解配置,内嵌tomcat功能
80.SpringBoot如何做全局异常处理
写一个类,在类上打上@RestControllerAdvice注解,然后写一个方法,在方法上打上@ExceptionHandler注解,然后在注解后面写上要捕捉的异常类型,如果还需要响应状态码的话需要打上@ResponseStatus注解
81.@SpringBootApplication注解的含义
是SpringBoot的核心注解,表示该类是启动类,并开启自动配置
82.spring-boot-starter-parent的作用
SpringBoot的父工程,目的是统一管理依赖的版本号
83.spring-boot-starter-web的作用
web项目的基本环境,集成了日志,tomcat,Json,SpringMVC等支持
84.SpringBoot中如何读取配置
@Value:用于读取一两个配置信息
@ConfiguretionProperties:用于多个配置信息
85.SpringBoot中日志的level有哪些
Error—>Waring—>Info—>Debug—>Trance
86.SpringBoot中如何管理事务
分为两种方式:
xml:通过DataSourceTransactionManager和TransactionManager实现
注解:在启动类打上@EnableTransactionManagement,然后再需要管理事务的类打上@Transaction
87.SpringBoot自动配置原理
首先自动配置的话必须在启动类打上@SpringBootApplication,然后@SpringBootApplication是一个包含注解,其中@Configuration、@ComponentScan和@EnableAutoConfiguraaion注解,然后@EnableAutoConfiguration注解会找到所有以AutoConfiguration结尾的自动配置类,并对其进行加载
88.SpringBoot启动流程
1.根据classpath创建一个ApplicationContext
2.注册一个CommandLinePropertySource来曝光命令行的参数作为Spring的属性
3.刷新ApplicationContext来加载所有单例的bean
4.触发CommandLinePropertySource的实例bean的run方法
89.MyBatis中${}取值和#{}取值的区别
#防注入,底层基于PreparedStatement对象,还能支持预编译,$不防注入,因为底层使用的是Statement对象,然后能用#就用#,但是像sql语句拼接表名这种就只能使用$
90.MyBatis关联查询中,延迟加载和饥饿加载的区别
延迟查询是在需要用到关联数据的时候才会查出来,而饥饿加载是不管用不用直接查出来
91.MyBatis对象关联查询和集合关联查询怎么做
associate :用于对象的关联查询,用javaType定义类型
collection:用于集合关联查询,用ofType定义泛型
92.MyBatis一级缓存和二级缓存的区别
缓存:就是将数据库中查出来的数据放入缓存中,然后在下次查数据的时候就可以直接从缓存中取,从而减少数据库的压力
一级缓存:SqlSession,是默认开启的,然后是在同一个SqlSession发送同一个sql时触发的,生命周期时调用SqlSessiong.close方法时结束
二级缓存:NameSpace,是在同一个Namespace发送同一个sql时触发,生命周期是程序结束
93.MyBaits的Mapper接口没有实现类为社么可以用@Autowired直接注入
因为使用了动态代理,当在调用对象时,jdk会自动代理生成一个代理对象,然后通过反射获取接口中的方法
94.在MyBatis如何动态修改SQL
拦截器95.MyBatis的动态SQL标签有哪些?
foreach遍历,where条件,if判断96.Mybatis的mapper如何传递多个参数
最常用的就是通过map传值,sql中通过key取值,然后也可以在形参上打上@Param注解,sql中使用定义的参数名取值
97.Mybatis,关联对象查询,使用嵌套子查询和JOIN连表有什么区别
join查询的时候只需要一条sql就能查询出数据,而嵌套子查询可能会需要很多条sql查询,性能很低
98.为什么要使用连接池
因为对数据库的操作都需要通过连接,如果每次都先获取连接,然后操作再关闭的话很消耗性能,所以就可以将常用的连接放入连接池中,从连接池中获取连接从而节省性能
99.讲一下你理解的Redis,为什么Redis很快
redis是一个高性能的noSql数据库,可以对数据进行持久化操作,基本类型的话有String,list,hash,set,zSet,然后因为它的数据结构简单,而且在内存中读写,所以速度很快
100.你常用的Redis的数据存储结构有哪些,他们的使用场景分别是什么
String,List,Hash,Set,Zset,String可以用来做缓存,List用来做队列和秒杀,Set可以用来去重
101.你们项目是怎么用Redis的
我们用Redis来解决前后端的交互问题,和验证码
102.怎么防止Redis宕机数据丢失问题
将redis中的数据持久化,就是将数据备份一份到磁盘中,一旦redis宕机重启后就可以使用备份文件恢复数据;然后redis的持久化一共是两种方式,一个是AOF,另一个是RDB,这两个持久化方式是搭配起来用的,因为RDB是快照保存,所以不可能百分百保证数据完整性,然后AOF的话是将所有的写命令都保存在日志里,恢复起来很慢,所以要搭配使用
103.Redis持久化是什么?有几种方式
104.Redis有了AOF持久化为什么还要RDB?
105.Redis内存不够了怎么办?
1:加内存
2:集群
3:使用淘汰策略,淘汰一些老旧的数据,然后淘汰策略的话最常见的有
volatile-lru :从已设置过期时间的数据集中挑选最近最少使用的数据淘汰
volatile-ttl:从已设置过期时间的数据集中挑选将要过期的数据淘汰
allkeys-lru:从数据集中挑选最近最少使用的数据淘汰
allkeys-random:从数据集中任意选择数据淘汰
no-enviction:不使用淘汰
106.你们Redis用在哪些业务上?用的什么存储结构
主要是用String来做缓存,像验证码,登录信息这种
107.淘汰策略有哪些?你们用的哪种
我们主要用的volatile-lru跟volatile-ttl
108.Redis事务和Mysql事务的区别
Mysql的事务是根据日志来实现的,操作一组数据时同时成功才成功,而redis是基于队列实现的,如果有一组数据操作失败了,其他数据不会回滚
109.使用Redis如何实现消息广播
通过发布订阅发布来实现广播的,订阅者订阅了该频道之后,发布者向该频道发送消息,所有订阅者就会收到消息
110.为什么要使用Redis做缓存
因为redis快啊,然后还可以减少数据库的访问量,降低数据库压力
111.缓存的执行流程
客户端发起请求,判断缓存中是否有数据,有就直接返回,没有的话从数据库中查询,再把数据放入redis中,最后响应数据
112.你们怎么保证Redis和Mysql的一致性
延时双删,我们是在数据库有增删改操作时先删除redis的数据,然后数据库操作完毕时先睡线程一下再删除一次,下次有查询操作进来时再将查出来的数据放入redis当中
113.SpringCache常用注解
@EnableCaching:开启SpringCache
@Cacheable:打在类上,表示该类中的所有方法都开启SpringCache
@CachePut:用于增改操作
@CacheEvit:用于删除操作
@Caching:组合操作
114.了解缓存击穿,穿透,雪崩吗?怎么处理?
击穿:缓存中没有的数据,但是数据库中有,比如当数据刚好过期但是有请求进来时,此时大量的请求就会直接访问数据库,增加数据库压力
解决方案:设置热点消息永不过期,设置双重互斥锁,就是只允许一个线程访问数据库
穿透:缓存数据库中都没有的数据,此时大量的请求就会直接访问数据库,增加数据库压力
解决方案:使用布隆过滤器,或者将没有值的key全部设置为null
雪崩:当数据同一时间大量过期时,此时大量的请求就会直接访问数据库,增加数据库压力
解决方案:设置热点信息永不过期,或者设置随机过期时间
115.Redis的主从有什么优点,和缺点?
主从就是redis的一种集群方式,然后可以分担读的压力,还可以备份数据,但是不能分担写的压力,并不能解决单点故障问题
116.解释一下Redis的哨兵模式。哨兵的不足?
哨兵模式就是可以监控主从服务器的健康状态,然后一旦主服务器宕机之后,可以将从服务器升级为主服务器,但是它也不能解决写的压力,因为它也是主从模式
117.Redis的cluster集群怎么存储数据的?
cluster是根据哈希槽来分配的,它范围是0-16384,然后当我set一个key的时候它就通过crc16算法得到该槽位,然后再把key放进去
118.什么情况下Redis集群不可用?
当主服务器出故障时,又没有子服务器用时,redis集群就不可用
119.Redis存储结构底层有没有了解?什么是SDS
基于SDS,就是简单动态字符串,它是redis自己封装的字符串结构,然后可以解决二进制安全问题和缓冲区溢出120.Redis如何模拟队列和栈,用什么命令
都是用list,同一边进同一边出就是栈,一边进一边出就是队列
121.Redis存储单个对象怎么存,存储对象集合怎么存
单个:String
集合:Hash,可以通过field快速取值
122.你们Redis用来做什么?使用的什么结构?
我们做了像用户登录时的Token,和验证码,用的String结构
123.统计全国高考前20名用什么?
ZrerangeBySocre
124.从100个VIP用户中随机抽取5名怎么做?
SrandMember
125.RabbitMQ的使用场景
解耦:生产者跟消费者通过MQ来交互
消除峰值:先来的先处理,比如一个请求要处理很久的时候,这时其他的请求都会放在消息队列中,等待处理
异步:提升程序性能
提高服务稳定性:可以通过手动提交来防止消息不丢失,因为用户不确定的话,消息就会一直在队列中不会删除
126.RabbitMQ如何防止消息丢失
手动签收
做消息持久化,前提是交换机跟队列也进行了持久化
127.RabbitMQ的交换机有哪几种
Fanout:广播模式,连接了交换机的队列都可以收到消息
Direct:定向模式,指定队列收到消息
Topic:统配模式,指定一些队列可以收到消息
128.消息是如何从发送者到达消费者的(RabbitMQ工作流程)
发送:生产者先和Broker,就是代理服务器建立Tcp连接,然后创建通道Channel,生产者就可以通过通道给Broker发送消息,最后由交换机Exchange发送消息给指定队列
接收:消费者也是先和Broker建立连接创建Channel,然后会监听指定的队列,一有消息发送到队列,Broker就会把消息推送给消费者
129.如何防止消息重复消费
重复消费的话就是指一般消费者在签收时出现网络波动,导致一条信息发送了两条,然后我们可以在每条消息上都绑定一个唯一id,然后当消费者收到消息之后可以去查询数据库,如果id不存在就是正常消费,存在的话就是重复消费,直接抛弃
130.RabbitMQ消息投递失败,你们怎么处理
我们是通过confirm回调来处理的
131.Lucene创建索引原理
通过倒排索引,先分词,然后转换大小写和时态,最后通过字母排序
132.ES的keyword和text区别
keyword:可以分词,然后还支持聚合查询,可以用于存储名字这种字段
text:不可以分词,不支持聚合查询,然后使用来保存像地址这种字段
133.ES的优势
ES是基于Lucene的开源搜索引擎,然后它更加容易上手,然后它的每个字段都可以通过索引搜索,还可以通过Restful风格与客户端交互
134.Lucene/ES为什么那么快(ES用到什么数据结构)
因为ES使用的是倒排索引结构,我们MySQL的查询的话是根据表去找数据,然后ES是根据数据去找表,然后还使用了二分查找
135.ES的分层结构,index下面是什么
index是库,然后是type,相当于表,Document,相当于行,Field,相当于列
136.讲几个ES中的查询对象:比如TermQuery
TermQuery:不分词
MatchQuery:分词
BooleanQuery:条件查询
RangeQuery:指定范围
MatchAllQuery:全部查询
137.你简单描述ES的DSL语法
DSL分为两个部分,DSL过滤和DSL查询,DSL过滤就是模糊查询,DSL查询就是精准查询
138.你说一下 match和term的区别?
match可以分词查询,但是term不能分词查询,比如像查询的时候term会将关键词一整个进行查询,完全匹配才会返回查询结果,而match是将关键词分词,分词后任何一个关键词能查询到都会返回结果
139.你使用过ES的哪些聚合查询?
求和,最大值,最小值,平均数,还有总个数,分类,以及去重
140.ES高亮怎么做的?
我们其实就是通过HighLightBuilder对关键字追加了一个红色字体,然后使用esTemplate的queryByPage方法获取结果再手动封装返回
141.你们ES和数据库的数据一致性怎么做的
我们是在更新数据库时同时对ES进行更新
142.ES分片机制了解吗
就是分为主分片和副分片,然后主分片的的话主要负责写,副分片会备份主分片的数据,同时分担读的压力,然后主分片一旦定义了数量就不能更改了,副分片则可以
143.描述一下ES添加文档的过程
首先客户端会请求一个协调节点,然后协调节点会进行路由选择一个Primary Node就是主分片,随后主分片的节点的数据全部保存完毕之后会同步到副节点,最后协调节点发现主分片和副节点的数据都保存完毕之后就会将结果返回给客户端
144.数据节点存储数据详细流程
145.详细描述一下Elasticsearch获取文档的过程
首先客户端请求一个协调节点,通过hash路由将请求转发到对应的节点,然后会使用轮询在主节点和所有副本中随机选择一个来实现读的负载均衡,随后接受到请求的节点将数据返回给协调节点,协调节点再返回给客户端
146.详细描述一下Elasticsearch搜索过程
客户端请求一个协调节点,然后协调节点将搜索请求分配到所有分片对应的主分片或者副本,然后所有分片将自己的搜索结果,就是doc_id,返回给协调节点,协调节点对这些搜索结果进行合并、排序、分页等操作再去用这些doc_id查询对应的数据,最后返回给客户端
147.详细描述一下Elasticsearch更新和删除文档的过程
由于ES中的文档是不可变的,所以这两个写操作不是真正的修改了原文件,删除的话就是ES中有一个.del文件,当删除请求发送后,.del文件会将该文档标记为删除,最终在合并的时候不会返回该文档,而修改也是一样,修改是直接将原文件标记为删除文件,所以在最终的合并后也不会返回该文件
148.ES有几种节点类型?他们的作用分别是什么
master:主要负责集群的范畴变更,例如操作索引,操作节点
data:用来储存索引数据节点的,主要用来操作文档
client:负责负载均衡
149.ES集群的三种颜色代表什么
绿色:集群健康健康状态,所有的分片和副本都可以使用
黄色:亚健康状态,就是分片可以使用,但是副本已经不能使用了
红色:不健康,表示分片都已经有损坏了,需要尽快维护
都代表集群的健康状态
150.你们项目怎么使用ES
我们是使用的SpringBoot集成了ES然后用来进行大量信息的搜索
151.说一下security中的的filter
SecurityContextPersistanceFitler:用来保存用户信息,然后有三个核心对象,SecurityContextHolder:绑定用户信息和当前线程,SecurityContextRepository:储存SecurityContext,SecurityContext:当前用户信息
UsernamePasswordAuthticationFilter:用来进行认证
BasicAuthticationFilter:基本过滤器,携带基础的认证界面
ExceptionAuthticationFilter:捕捉异常
RemembermeAuthticationFilter:记住我功能
SecurityInterceptorFilter:完成授权
152.说一下security的认证原理
首先UsernamePasswordAuthticationFilter会拦截请求,把用户信息封装成一个token,再调用AuthticationManagement进行认证,然后AuthticationManagement会调用AuthticationProvider进行认证,Provider再调用UserDetailsService获取数据库中的用户信息,然后使用密码编译器对密码进行对比,认证成功后返回一个Authtication,随后请求回到UsernamePasswordAuthticaionFilter,调用SecurityContextHolder将Authtication封装成一个SecurityContext,保存到SecurityContextHolder中,最后SecurityContextPersistanceFitler会调用SecurityContextRepository保存SecurityContext,再清空SecurityContextHolder
153.什么是集群
集群就是为了解决高并发问题和防止单点故障将应用复制成相同的几个应用一起工作,但是集群维护起来较为困难,同时我们进行了集群之后就需要解决怎么将请求分配到多个服务器,此时我们就可以使用负载均衡的轮询,权重,随机等等算法来解决分配请求问题
154.什么是负载均衡
用来分配请求,使用轮询,权重,随机等算法将请求路由到不用的服务器
155.什么是分布式
就是将应用按照业务需求分成多个子应用,将子应用单独放在不同的服务器上运行,服务之前通过api调用,分散了服务器的压力,还解决了高并发问题
156.集群和分布式的区别,分别解决什么问题
集群的话是将应用复制成多份,然后单独部署运行,能解决单点故障问题,而分布式的话是将一个应用拆分成多个子应用,无法解决单点故障问题,同时集群的话项目本身的代码依然臃肿,而且耦合性很高,分布式的话就完美解决了这两个问题,然后我们一般可以将集群和分布式配合使用,对分布式中负荷比较大的服务进行集群
157.说一下你理解的微服务
微服务就是一个个微小的服务,然后可以独立部署运行,然后服务之间通过Restful风格的请求进行交互,同时解耦
158.什么是CAP理论 , 哪些技术用到AP,哪些用到CP
C:Consistency(一致性)
一致性分为两种:
强一致性:就是保证数据写入什么,读出就是什么,这样做的话性能非常低,因为要保证所有的数据副本都要一致
弱一致性:弱一致性的话就是不保证能当时就读出新数据,也不能保证什么时候能读出新数据,但是会尽量保证某个时刻数据一致
最终一致性:是弱一致性的加强模式,它可以保证在一定的时间内读出新数据,比如像我们平时退款的时候,都会给一个提示,退款将在多少小时内到达账户
A:Availability(可用性):
这个是根据需求来定义的,比如像在进行搜索的时候,200毫秒就显示数据了,那就可以认为这个系统是可用的,而如果1分钟才显示结果的话,那这个系统肯定是不可用的
P:Partition Tolerance(分区容错性):
当分布式系统出现网络分区,就是几个节点中的一个节点出现了故障,然后节点之前不联通时,依然可以提供服务,但是这样的话就不能保证三个特性一起使用了,所以我们需要抛弃一些特性比如:
CA:分布式中是绝对不可用的,因为一致性在修改数据是其他节点是不可用的,这点就和可用性发生冲突了
AP:保证可用性和容错性抛弃一致性,系统短时间内不一致就可以考虑,比如像常见的mysql,eureka就是AP
CP:保证一致性和容错性抛弃可用性,系统短时间内不可使用就可以考虑,像redis跟zookeeper这种就是CP,但是基本不会选择这种组合,因为一旦网络故障就会导致系统瘫痪
159.什么是强一致性和最终一致性
强一致性:强一致性是要保证所有数据副本都一致,就是写入什么读出什么,这样的话效率会非常低,因为需要同步
最终一致性:最终一致性就是弱一致性的一种加强模式,会保证在一定的时间内读出最新数据,就比如退款,我们退款的话一般都会弹出一个退款将在多少小时内到账,这种就是最终一致性
160.什么是Base理论
Base理论的话也是一个组合单词分为
BA:Basically Available(基本可用):
就是指系统在发生故障之后可以允许一部分可用性损失,比如像
响应时间损失:原本200ms就可以返回的结果,由于发生了故障,1-2秒才返回
系统功能损失:就是像双11的时候我们去买东西一样,当访问量突然暴增的时候,此时系统部分功能不可用了,然后一部分用户就会被引入一个降级页面
S:Soft State(软状态):
就是允许在不同节点间的数据同步存在延迟,比如我们去买东西,然后那个地方的网络非常差,当时给了钱没提示,然后到了网络好的地方就弹出消息了
E:Eventually Consistent(最终一致性):
就是在数据副本同步的时候保证一段时间内可以读出最新数据,比如退款
161.讲一下你们公司微服务解决方案
上家公司的话我们使用的是Netflix的全家桶,
用Eureka做服务中心,实现服务的注册、发现和续约
OpenFeign做轮询,实现分配请求
Hystrix做熔断,实现降级
Zuul做网关,实现所有请求的统一入口
Config做配置中心,用来统一管理配置
Bus做微服务广播,配合config实现自动更新配置
Sleuth做链路追踪,快速定位故障节点
162.说一说Spring Cloud有哪些常用组件
Eueka:服务中心,发现服务和注册服务以及服务续约
Ribbon/OpenFeign:轮询,就是分配请求
Hystrix:熔断,做降级
Zuul:网关,请求的统一入口
Config:配置中心,统一管理配置文件
Bus:广播,配合Config实现自动更新配置
Sleuth:链路追踪,快速定位故障节点
163.Spring Cloud的优缺点?
优点:
第一肯定是为了解耦嘛,然后不同的服务还可以使用不同的语言编写,方便开发维护,还可以将服务集群部署,解决单点故障问题
缺点:
分布式事务十分繁琐,然后部署也比较麻烦
164.什么是服务注册
这个Eureka的话是分为客户端跟服务端吗,然后服务注册的话就是当客户端在启动的时候会将自己的地址端口打包发送给服务端,然后服务端会将信息保存起来
165.什么是服务发现
就是服务之间调用的时候,会根据Eureka中的注册表来找到对方的地址发送Http请求
166.什么是服务续约
客户端会根据keepAlived心跳机制每隔30秒向服务端自己的健康状态,然后服务端就不会将客户端从注册表中删除,而如果服务端连续90秒没有收到客户端的报告的话就会默认客户端已经宕机,会将客户端从注册表中删除
167.如果服务挂了,注册中心要等到90s后剔除,那么在剔除前的这段时间内,挂掉的服务有可能还是会被调用,怎么处理?
可以使用Hystrix熔断降级机制,给客户端返回托底数据
168.你知道EurekaClient服务发现和服务续约每隔30s做一次请求是用什么技术实现的吗?
是通过Spring自带的定时任务Scheduled实现的,先判断服务发现或者服务续约功能是否开启,如果开启了的话就会获取时间间隔,再初始化定时任务
169.Ribbon是什么,Ribbon的工作原理讲一下
Ribbon是负载均衡器,就是用来实现分发请求的,然后当请求来了之后,Ribbon会拿着服务名去服务注册表中查找服务,然后根据负载均衡算法选择一个地址发起Http请求,然后常见的负载均衡算法的话有像轮询,权重,随机,区域等等,轮询是Ribbon默认的算法
170.说一下 Ribbon的工作原理
就是请求来了之后,Ribbon会拿着服务名去注册表中查找,然后使用负载均衡算法选择一个地址发送Http请求
171.Ribbon有哪些负载均衡算法,怎么配置
轮询,一个一个来
权重,能者多劳
随机
区域,根据区域选择
172.OpenFeign和Ribbon的区别
OpenFeign是包含了Ribbon和Hystrix的,然后OpenFeign使用的是声明式编程,所以代码更加简单
173.OpengFiegn的工作流程
当程序启动的时候,Feign的服务端回去扫描带有@FeignClient注解的客户端,然后把其交给Spring管理,
当请求发起的时候,会使用动态代理,对每个方法生成RequestTemplate,再交给HttpClient,最后由Ribbon发送请求
174.为什么要使用Eureka 为什么要使用Ribbon 为什么要使用config配置中心
Eureka:因为在微服务中各服务的交互是需要地址来完成的,Eureka就是用来发现服务然后保存服务地址的
Ribbon:因为微服务中有那么多服务,谁知道请求是给哪个服务的,就用Ribbon来路由请求
Config:因为每个微服务都有自己的配置文件,然后那么多配置文件的话不好管理,所以就使用了Config来统一管理配置
175.什么Feign的客户端接口没有写实现类也可以直接被依赖注入
因为feign是使用了动态代理,为每个方法都生成requestTemplate,然后它会根据服务名找到对应的服务
176.介绍一下Hystrix
当某个服务因为未知因素宕机时,就可以使用Hystrix对其进行一个熔断降级处理,就是在被调用时返回一个托底数据
177.什么是熔断,什么是降级
熔断的话是当一个服务宕机之后,让其暂停服务
降级就是配合熔断,返回一个托底数据
178.什么是资源隔离?
资源隔离就是限制一个服务对资源的使用,也就是限流,然后资源隔离分为两种方式:
线程池隔离:就是专门用一个线程来放置等待的请求
信号量隔离:就是处理请求和等待的请求在同一个线程中,然后通过一个计数器来记录请求量,一旦超过最大请求数的时候就直接拒绝之后的请求
179.资源隔离:信号量和线程池的区别
线程池隔离:就是专门用一个线程来放置等待的请求
信号量隔离:就是处理请求和等待的请求在同一个线程中,然后通过一个计数器来记录请求量,一旦超过最大请求数的时候就直接拒绝之后的请求
180.对于CAP理论,Eureka选择的是AP还是CP?它保证了一致性还是可用性?
Eureka的话是跟MySQL一样选择了AP理论,就是选择了可用性和分区容错性,可以接受一段时间内数据不一致
181.说一下Eureka的自我保护
就是为了防止数据被误删,Eureka不会立刻删除过期的服务,然后在开发阶段的话我们可以关闭自我保护机制,因为为了防止在调用服务时Eureka获得到已下线的服务从而导致数据错误
182.你们项目是如何做服务降级的?
在我们项目里就比如像秒杀服务,我们是使用了redis实时查询库存,然后通过Hystrix来限制最大信号量,一旦超过最大信号量的话就会返回托底数据
183.Zuul有哪几类Filter,他们的执行顺序是怎么样的?
zuul是分为pre前置过滤器,route路由过滤器,post后置过滤器以及error异常过滤器,流程的话是先经过前置过滤器到达路由过滤器分发请求,最后通过post过滤器返回,然后一旦发生错误的话都会进入异常过滤器
184.在Zuul中做登录检查如何实现?
我们是使用pre前置处理器拦截下请求,然后从请求中获取token,如果没有token的话就会跳转到登录页面
185.在Zuul中如何做限流?
我们是使用了Hystrix的资源隔离模式,限制了线程池最大连接数和信号量最大数
186.配置中心解决什么问题?
因为在分布式项目中每个服务都有自己的配置文件,不方便管理,所以就可以使用配置中心来统一管理配置文件
187.EureakServer的搭建流程
1:导包
2:在启动类上打上@EnableEurekaServer
3:最后在yml中配置端口号和地址
188.Ribbon的整合流程
1:导包
2:在restTemplate的Bean定义方法打上@loadBalance注解
3:修改url,将地址改为服务名
189.Feign的整合流程
1:导包
2:在服务端打上@EnableFeignClients
3:客户端打上@FeignClient,将目标服务的方法copy过来放到Feign接口中
190.Hystrix的整合流程
1:在Feign的yml中配置开启熔断
2:然后写一个类实现FallBackFactory接口,在类中编写降级方法,最后在@EnableFeign标签中标识降级类
191.Zuul的整合流程
1:导包
2:在启动类打上@EnableZuulProxy注解
3:yml中配置放行路径,禁止路径和统一前缀
192.你们ZUUL做了写什么
我们是用Zuul做网关,管理微服务地址的统一入口
193.ConfigServer的整合流程
服务端:
1:导包
2:启动类打上@EnableConfigServer注解
3:yml文件中配置远程仓库和账号密码
客户端:
1:导包
2:创建bootstrap.yml文件,然后配置配置中心的地址和要拉取的文件名和环境
194.你们微服务项目的技术栈描述一下
前端管理系统:Vue+ElementUI
前端门户系统:Html+Css+Js
后端系统:SpringCloud,SpringMVC,MybatisPlus,ES,Redis,RabbitMQ,Oss
195.浏览器发起一个请求,在你的微服务项目中的怎么去执行的?
首先会通过Nginx,通过负载均衡算法分配给Zuul,然后Zuul会进行验证,验证完成了就会去配置中心拉取服务地址,通过Ribbon对对应的服务发起调用,最后返回
196.说下Ribbon和Feign的区别呢
Feign的话是集成了Ribbon和Hystrix的,然后相对于Ribbon来说的话操作还更为简单,因为Ribbon是配合restTemplate来发送请求的,还需要在restTemplate的bean方法上打上@loadBalance注解,而Feign的话只需要打两个注解就可以使用了
197.Spring,SpringBoot和SpringCloud的关系以及区别
Spring的话是一个轻量的容器框架,代码简单,功能强大,然后核心功能分为IOC和AOP
SpringBoot是基于Spring的一个框架,对Spring进行了大量的简化,比如像基于注解配置和内嵌tomcat之类的
而SpringCloud的话是基于SpringBoot的一个框架,然后对单体项目进行了解耦,然后可以将服务集群部署和解决单点故障问题
198.什么是分布式事务
分布式事务就是在分布式项目中一个请求可能会涉及多个数据库,为了保证数据统一性的话就需要使用分布式事务
199.分布式事务你知道哪些解决方案? 这些方案如何选型
分为2PC、TCC、可靠消息最终一致性和最大努力通知
2PC:把整个业务分成两个阶段,P是准备阶段,C是提交阶段,准备阶段时,TM会向所有的参与者发送请求,当所有参与者都准备ok时就会提交事务,如果出现一个error就会回滚事务,可以用来保证强一致性
TCC:是一个补偿性的事务,分为Try-Confirm-Cancel,Try的时候是准备工作,Confim是提交,Cancel是回滚,一般会用于登录送积分这种场景
消息可靠最终一致性:当事务完成时,事务发起方会发出一条消息通知参与方,并且他们一定能接收到消息处理事务。适用于执行周期长,但是实用性不高的场景
最大努力通知:在不入侵业务的情况下,尽可能的保证数据一致性,类似于支付结果
200.什么是2pc
2pc就是将整个事务分为了两个阶段,分别是准备阶段合提交阶段,在准备阶段,TM会向所有的参与者发送请求,当所有参与者都准备ok时就会提交事务,但是一旦有一个参与者出现error的话就会回滚事务
缺点:
如果有一个参与者迟迟不回复的话,就会造成事务堵塞,然后如果当事务处理器提交了事务后就宕机了,这时一部分参与者提交了事务,而一部分没有收到消息,是没有提交事务的,此时就出现了脏数据
200.Seata相比传统XA方案2PC有什么区别,以及优点?
性能好,不会长时间占用连接资源,而且对业务代码0入侵,也就是注解使用
201.Seata的TC,TM,RM的含义,以及作用?
TC:事务协调器,接受TM发起的全局事务提交和回滚,负责与RM通信,及通知RM进行事物的提交还是回滚
TM:事务处理器,负责开启一个全局事务,然后向TC发起全局事务的提交与回滚
RM:控制分支事务,接收TC的提交回滚命令,然后通知各个分支进行提交或回滚
202.解释一下Seata的工作原理
1.当事务到达时,TM回向TC注册一个全局事务,得到一个xid
2.然后TM会将xid分配给各个RM,RM向TC注册事务并和全局事务绑定
3.业务逻辑开始时,RM会将原数据存入undo log中,然后向TC提交本地事务结果
4.TC会根据每个RM提交的事务结果判断是否回滚
5.如果所有本地事务都成功的,TC就会向TM发起全局事务提交命令,然后TM会删除undo log
6.如果有本地事务失败的话就会通知TM回滚,然后TM会根据undo log的恢复数据并提交事务
203.你能简单描述一下你在项目中是如何集成Seata的吗
1.导包
2.yml中配置事务组名,同时添加file.conf和registery.conf
3.配置datasource
4.数据库中添加undo log表
5.业务方法打上@GlobalTransactional
203.1. 没有Seata或者TCC这些事务框架,你可以怎么处理事务?
我会参考TCC思想,考虑自己实现异步操作数据库方案,如果失败就做补偿
204.你说一下什么是分布式锁
分布式锁就是为了解决分布式项目中多线程造成的线程安全问题,通过会用zookeeper或者redisson实现
205.分布式锁有哪些解决方案
1.使用CAS思想在数据库冗余一个version版本字段,然后如果操作过一次了就+1,然后其他线程来操作时就会无效
2.使用redisson实现
3.使用基于zookeeper实现的框架curator
206.Redis如何实现分布式锁,用什么命令,会出现什么问题?
因为需要设置锁的自动过期时间,所以我们可以直接使用redisson,创建锁时就可以设置过期时间
出现的问题的话就是在上锁的时候万一redis的节点挂了就会导致加锁失败,所以我们就可以使用redisson的红锁来实现
207.你项目中怎么使用分布式锁的
redisson
208.了解Redission的看门狗原理吗?
底层使用了定时任务每10秒检查一下锁,如果还未执行完毕的话就会增加锁时长,每次30秒
209.你在项目中如果使用ZK实现分布式锁的?
直接用基于zookeeper实现的框架curator
210.创建线程是几种方式
1.继承Tread类重写run方法
2.实现Runnable接口重写run方法
3.实现Callable接口重写call方法,然后将返回值作为FutureTask的参数
211.Thread的start和run的区别
start会开启新线程,run不会
212.sleep 和 wait的区别
wait是Object的方法,会释放锁资源,sleep是Tread的方法,不会释放锁资源
213.线程的几种状态
新建,就绪,等待,阻塞(等待阻塞,同步阻塞,其他阻塞),死亡
214.Synchronized 和 lock的区别
首先都是用来保证线程安全问题的,然后synchronized是由jvm维护的,而且是非公平锁,不能确认锁状态,所以适用于并发较少的场景,而lock是可公平锁,可以确认锁的状态,所以适用于高并发的场景
215.你知道AQS吗
AQS的全称是AbstractQueueSynchronizer,是一个抽象类,我们常用的ReentrantLock的实现就得依赖这个类,因为它给提供了一个FIFO队列,就是会将没有获取到锁的线程放入这个队列中进行等待
216.悲观锁和乐观锁
悲观锁:会提前对数据上锁
乐观锁:当修改数据提交时才会对数据进行检测是否冲突
217.你知道什么是CAS嘛
CAS就是Compare And Set,当修改值时,只有当预期值与现值一样才会进行修改
\218. Synchronized 加非静态和静态方法上的区别
不加Static的话这个类的实例对象就不会被多个线程共享
219.Synchronized(this) 和 Synchronized (User.class)的区别
Synchronized括号里的参数是需要唯一的,但this是指该调用方法的线程的实例对象,从而不是唯一的,所以锁不住,而User.class是该类的字节码文件,肯定是唯一的
220.Synchronized 和 volatitle 关键字的区别
首先是能修饰的地方,volatile只能修饰变量,然后synchronized还可以修饰方法和代码块,其次是阻塞,多线程访问volatile线程时不会堵塞,而访问synchronized线程时会堵塞,最后是原子性,volatile不能保证原子性,synchronized可以
221.synchronized 锁的原理
基于底层互斥锁来实现的,通过monitor监视器进行计数,如果为0则可以访问资源,不为0就堵塞,然后是通过monitor exit将计数变为0的
222.synchronized 锁升级原理
偏向锁:当一个线程获取到锁之后会对其进行标记,之后该线程就可以直接访问资源
轻量级锁:当一个线程获取到锁之后,其他线程将进行自旋,也就是隔一段时间再获取锁
重量级锁:因为当锁竞争很严重时会有很多线程一直在自旋,很消耗性能,所以当某个线程自旋次数达到10次之后就会升级为重量级锁,当一个线程获取锁之后,其他线程会直接堵塞
223.乐观锁的使用场景(数据库,ES)
1.在ES中使用版本号控制线程安全问题
2.在数据库中用版本号防止线程安全问题
3.在Atomic中用CAS防止线程安全问题
224.AtomicInterger怎么保证并发安全性的
是基于CAS操作来实现的
225.什么是重入锁,什么是自旋锁,什么是阻塞
重入锁:允许一个线程可以多次获取锁
自旋:当一个线程获取锁后,其他线程每隔一段时间尝试获取一次锁
阻塞:当一个线程获取锁后,其他线程直接阻塞
226.你用过JUC中的类吗,说几个
Lock,ConcurrentHashmap,Atomic原子类
227.ThreadLocal的作用和原理
ThreadLocal是用来解决线程安全问题的,原理是ThreadLocal会为每个线程提供一个副本,然后将该副本作为key,我们储存的值作为值,所以在取值的时候只有该线程才能取到值,其他线程是访问不到的
228.线程池的作用
用来控制并发数量、达到线程复用以及管理线程生命周期的
229.Executors创建四种线程池
CachedTreadPool:缓存线程池,用来做短期异步
FixedThreadPool:定长线程池,用来做长期
SingleThreadPool:单个线程池,用来做顺序
ScheduleThreadPool:定时线程池,用来做周期
230.线程池的执行流程
当任务提交时如果大于核心线程数,就会将该线程放入工作队列当中,当工作队列满了就会将线程创建到最大连接数,如果此时还不能处理完任务就会触发拒绝策略
231.线程池构造器的7个参数
最大连接数,核心连接数,闲时时间,时间单位,线程工厂,任务队列,拒绝策略
232.线程池拒绝策略有几种
AbortPolicy:直接抛异常
CallerRunsPolicy:用提交了任务的线程来处理被拒绝的任务
DiscardPolicy:直接抛弃任务
DIscardOldestPolicy:抛弃在队列之前的老任务
233.你知道ScheduledThreadPool使用场景吗
就是带定时器的线程池,Eureka的心跳机制和拉取注册表就是通过这个线程池实现的
234.什么是索引
帮助数据库高效查询数据的一种方式,底层可能通过一些具体的数据结构来实现
235.Mysql索引有哪些类型
主键索引(主键,非空且唯一),唯一索引(唯一且可为空,用于身份证号、电话号码这种唯一性高的字段),普通索引(普通列上,允许值重复),还有个全文索引,但是基本不用
236.索引方式有哪些
一般就是B+树,还有个hash,但是MyIsam和InnoDB都不支持hash
237.Mysql的索引结构原理
采用了B+树的结构,因为B+树只会在叶子节点储存数据,其他节点都储存的key,所以树高更低查询更快,而且查询数据必须走到叶子节点才会返回数据,所以查询速度也稳定,然后叶子节点储存的数据是链表结构,适合进行排序和范围查找
238.InnoDB的索引结构和MyIsam的索引结构有什么区别
首先他们都是使用的B+树结构,但是InnoDB的叶子节点储存的是数据,MyIsam叶子节点储存的是数据地址,然后InnoDB辅助索引的叶子节点存放的是主键索引的键值,MyIsam储存的还是数据地址,最后InnoDB的索引和数据是放一起的,MyIsam则是分开放的
239.哪些列不适合创建索引
经常修改的字段,不经常查询的字段,唯一性不高的字段
240.哪些因素会造成索引失效
比如模糊查询是%放到左边时(向左匹配),还有or,in以及查询null时,索引都会失效
241.什么是辅助索引&什么是覆盖索引
辅助索引:也叫回表,就是通过辅助索引查询了之后还要查询主键索引
覆盖索引:通过辅助索引查询得到结果刚好包含在辅助索引的键值里,此时就不用回表
242.InnoDB辅助索引的叶子节点也存数据吗
不会,InnoDB辅助索引的叶子节点储存的主键索引的键值
243.组合索引的匹配原则
向左匹配
244.Like一定会让索引失效吗
%放到右边时就不会失效
245.索引创建的原则有哪些
频繁查询的字段就应该创建索引,而像不经常查询或者经常修改和唯一性不高的字段都不是适合创建索引
246.哪些因素可能会造成数据库性能问题
像不合理的业务需求,比如像实时更新浏览量,还有像表设计不合理,字段太多,以及sql语句不合理,太多的连表查询中使用了select
247.Mysql的执行流程是怎么样的
首先通过连接器,它会检查我们的用户信息以及权限,然后查询缓存,如果缓存中有就直接返回,没有就到达分析器,检查sql语句是否有错,没错就会到达优化器,优化sql,最后到达执行器,执行sql并返回结果
248.优化SQL你从哪些方面着手
这个其实有很多,然后常见的一般就像不适用select *,in,or,建立索引以及小结果集驱动大结果集(就比如嵌套for循环,把循环次数多的循环放在循环次数少的里面)
249.如何去定位慢SQL
可以查看mysql的慢查询日志,也可以使用show processlist命令
250.页面上发起的一个查询很慢,你怎么去优化
首先可以检查硬件和网络,再检查代码有没有问题,最后检查定位到sql,看一下需不需要进行sql优化,另外还可以建立索引和分表等操作
251.你如何看SQL有没有命中索引
在sql语句之前加上explain
252.mysql存储引擎有哪些,有什么区别,如何选择
InnoDB:用于修改多的场景,因为它支持外键和事务
MyIsam:用于查询多的场景,因为它支持全文索引,但是不支持外键和事务
Memory:用于数据不需要持久化,基本用不到
241.数据结构有哪几种分类
分为两种,逻辑结构和物理结构
逻辑结构:
集合,线性结构(例如数组,链表),树状结构(例如二叉树,多叉树),图形结构
物理结构:
顺序储存结构(例如数组),链接储存结构(例如链表),数据索引储存结构(建立索引来标明节点地址,通过索引查找),数据散列储存结构(就是将数据地址与关键字之间使用hash算法产生关系,加快查找速度)
242.数组和链表在内存中的存储结构有什么区别
数组:一般用来查询数据,因为增删的话需要改变其他值的地址,所以效率很低
链表:一般用来增删,因为链表增删的话只需要修改指针的指向即可,但是链表查询效率很低,因为链表不支持索引,所以需要遍历查询
243.说一下散列存储(Hash存储) , 什么是Hash冲突 , 有什么解决方案
hash冲突就是两个不同的key计算出了相同的地址,常用解决方案有:
拉链法:把这个key的值指向另一个地址
开放寻址法:一直计算到不冲突为止
再散列法:换种hash算法再计算一次
建立公共溢出表:将整个hash表一分为二,然后将发生hash冲突的值移到溢出表中
244.说说 数组,链表,循环,嵌套循环的时间复杂度
查询数组是O(1),链表是O(n),循环是O(n),嵌套循环是O(n2),三个foreach循环是O(n3)
245.JDK中线性结构的集合有哪些
数组(list,set),链表(likedList),栈(先进后出),队列(先进先出),串(String,StringBuffer,StringBuilder)
246.你说一下树形结构对比线性结构的优势
线性结构和树形结构最大的区别就是查询速度,因为树形结构可以使用二分查找,所以查询效率十分高
247.说一下树的分类,以及你对它们的理解
二叉树:
二叉排序树:查询增加效率高,但是容易倾斜为链表
平衡二叉树:二叉排序树的升级版,要求两颗子树的高度差不大于1,然后查询效率高,但是增改效率低,因为需要重新排序
红黑树:自平衡树,根节点和叶子节点都只能为黑色,然后红色节点只能在两个黑色节点之间,查询效率稍低于平衡二叉树,但是增改效率大大增加
多叉树:
B Tree:自平衡树,相比二叉树更适合与存储读写较大的数据块,因为它一个节点可以存储多个key,然后key越多,分叉越多,节点越少,深度越浅,所以查询效率更高
B+Tree:和B Tree一样都是自平衡树,但是B+Tree只会在叶子节点储存key和数据,其他节点都储存key,所以树高更低,查询更快,然后因为数据都储存在叶子节点,所以查询速度也稳定,而且叶子节点是形成的链表结构,更方便范围查找和排序
248.有是二叉树为什么要出现多叉树
因为二叉树在大规模的储存数据中树高会越来越高,所以导致IO效率非常低,而多叉树因为每层可以储存更多的数据,所以就能降低树的高度,从而提升查询效率
249.B-tree和b+tree的区别
和B Tree一样都是自平衡树,但是B+Tree只会在叶子节点储存key和数据,每层可以储存更多的key,所以树高更低,查询效率更高,然后因为数据都存在叶子节点,所以每次查询速度也稳定,而且因为叶子节点储存数据会形成链表结构,所以更方便范围查找和排序
250.说一下ES用到了什么数据结构
数据索引储存结构,ES是使用关键字与索引建立关系,然后通过索引去找数据,也叫倒排索引
251.什么是单例,如何实现
每个类中只有一个实例,避免频繁的创建对象和销毁,主要实现方式有:
懒汉模式:私有化构造方法,声明一个静态成员变量并new一个该类实例赋值,声明一个静态方法返回该实例对象
懒汉模式:私有化构造方法,声明一个静态成员变量但是不赋值,声明一个静态方法,进行判断,如果该对象有值的话就直接返回,没有值就new一个该类实例对象为其赋值再返回,同时懒汉模式会造成线程安全问题,可以通过双重校验锁来解决
枚举:直接定义字段
252.模板模式的作用
保证算法结构不被修改的情况下,允许子类修改其有些特殊步骤,例如redisTemplate
253.什么是适配器模式
将不可兼容的接口转换为可兼容的接口的中间类,例如handlerInterceptorAdaptor,让我们在定义拦截器的时候可以不用覆写所有方法
254.什么是代理模式?有几种代理?
不直接使用实际对象,而是通过使用代理对象来调用实际对象,主要分为静态代理,jdk动态代理和cglib动态代理
255.JDK动态代理和CGLIB动态代理的区别?
jdk动态代理需要实现接口才能使用,而cglib动态代理不需要实现接口而是通过修改目标类的字节码文件来实现
256.常见的设计模式说一下
单例模式:懒汉,饿汉,枚举
工厂模式:beanFactory
模板模式:各种Template
代理模式:spring的aop就使用到了代理者模式
适配器模式:各种adaptor
观察者模式:监听器
257.浏览器输入一个域名,它是怎么去执行的?
首先会去本地host文件里查看是否配置对应的ip,有就直接访问,没有的话就通过DNS服务器解析为ip然后再发起访问
258.请求在你的项目中是怎么执行的?
我们在项目中是使用了zuul作为网关,请求先到zuul,然后又zuul调用ribbon分配请求,服务之间使用openFeign进行通信,最后返回
259.如果zuul网关挂了怎么办?
集群,用Nginx做负载均衡到zuul,然后Nginx可以使用主备切换防止单点故障
260.如果有人用脚本刷你们的短信接口怎么办
可以获取到该请求的ip,当这个ip在短时间内发送了一定数量的请求时直接拒绝它的请求
261.非对称加密,什么是数字签名
首先,有非对称加密肯定就有对称加密,它们两个都是一种算法,用来保证数据传输安全的。
对称加密:是数据传输双方都使用相同的密钥,然后传输方加密,接收方解密还原数据,例如DES算法
非对称加密:是数据传输双方使用不同的密钥进行加密解密,分为公钥和私钥,公钥可公开,私钥不可公开,然后公钥是由数据接收方发送给传输方的,常见的非对称加密例如RAS算法
数字签名:数字签名就在非对称加密的基础上用私钥加密,公钥解密来防止数据被篡改
262.Oauth2的四种授权模式
授权码模式:就是通过授权码获取access_token
简化模式:直接从前端获取token,容易遭到攻击
用户密码模式:让用户自己输入账号密码登录
客户端模式:用户向客户端认证,然后由客户端向第三方索取资源
263.要求每天早上 1点统计前一天的平台注册人数,怎么做
使用定时任务每日结算即可,然后将人数保存
264.使用Quarterz定时任务做订单超时关单有什么问题
用quarterz的话扫描的时间间隔需要设置的很短,在单体项目中当然是没问题的,但是在分布式项目中的话这样就太消耗性能了,所以在分布式项目中我们最好使用redis或者rabbitmq做延迟队列实现订单超时
265.讲一下你做过的比较复杂的业务
商品发布实现,其实商品发布只需要将商品的状态修改为上线,然后将其放入ES中即可,但是商品涉及的表很多,在我们项目中是设计了商品主表,商品详情表,商品市场表,商品类型表。商品主表和详情表、市场表都是一对一关系,然后通过共享主键实现的,商品类型表的话就是多对一关系了,我们采用了在主表中添加类型id来实现
266.什么是RBAC , 相关表怎么设计的?
RBAC是Role-Based-Access-Contro的缩写,就是基于角色控制权限,基本思想是权限不会直接赋予用户,而是在用户和权限之前创建一个角色来关联用户权限,我们项目中是设计了用户表,角色表,用户角色关联表,权限表,角色权限关联表
267.在VUE中,什么是MVVM
MVVM是Model-View-ViewModel的缩写是一种架构,其中Model是用来操作数据的,View展示结果,然后ViewModel是将Model和View关联起来
268.讲几个VUE的指令
v-for:循环
v-text:追加文本
v-html:追加页面文本
v-if:判断
v-on:绑定事件
v-bind:绑定属性
269.webpack的作用
VUE项目是必须使用webpack打包后才能部署的,其次它可以将ES6等高级语法转换为各个浏览器都认识的语法
270.Vue中定义组件分为几种,有什么区别
全局组件:所有VUE都可以使用
局部组件:只有在当前VUE中可以使用
271.讲一下你用过ElementUI的哪些组件
form表单,button按钮,text文本框,radio单选框等等
272.你们Redis做登录是怎么处理登录信息过期的?
我们是给token设置了过期时间来处理登录信息过期的,然后为了防止已登录的用户访问突然中断,我们在接收到用户的请求后将token重新设置到redis
273.讲一下你们的登录实现方案
当用户第一次登陆时,我们后台会生成一个token放入redis中,再将token传输给前端,前端用localStorage储存token,再使用axios拦截器在每次发送的请求中都携带该token,后端接收到token后就可以进行查询
274.三方登录流程讲一下
1.用户发起微信登录请求
2.后台重定向到扫码登录界面
3.用户扫码后后台获取到授权码
4.后台通过授权码去获取token
5.通过token获取openId
6.然后根据openId查询微信用户表:
如果查到用户且关联了本地账户的话就直接免密登录
如果查到用户但是没有关联本地账户就跳转到关联页面
如果没有查到用户,就向微信发起请求获取用户基本信息,添加到微信用户表中再跳转绑定页面
7.通过手机号查询是否绑定了本地账户
275.京东的首页的商品分类,让你设计表,你怎么设计
一个典型的自关联关系,所以我们首先肯定要设计一个id和parentId,然后是商品名,创建时间,修改事件,上下架时间,商品数量,排序,商品图标
276.如何查询出树状结构的课程分类数据
在实体类中追加一个子类children字段,查询的时候使用嵌套for循环将所有的层级都查询数据,除了第一级,其他子类都关联到自己的父级,最后返回第一级
277.你们系统使用Redis缓存了哪些东西?用Redis的什么结构去存储的?
登录token,验证码,商品分类,都是String
然后购物车用的是Hash
278.课程发布流程讲一下
先将课程的状态修改为上线,然后再将其放入ES中
279.你们课程相关的表是怎么设计的?主要的字段说一下
我们是设计了课程主表,课程详情表,课程类型表,和课程市场表,主表和详情表、市场表都是1对1关系,所以我们采用了主键共享的策略解决的关联关系,而类型表和主表是多对一关系,所以我们在主表中设置了typeId属性关联
主表主要包含id,name,typeId,state,以及typeName等等
详情表有id,简介和详情
市场表包含id,价格,活动时间,活动过期时间
类型表包含id,类型名,创建时间,课程数量,父id等
280.讲一下你们这个项目的主线业务
我们分为两大版图,第一个是培训机构入驻,发布课程,以及企业入驻,发布招聘信息,第二是普通用户可以选择购买课程学习或者应聘
281.你们项目最大并发是多少
开发的时候是按照2000qps设计的,但是具体的并发数是运维在统计,所以我也不是太清楚
282.你们项目最大表数量是多少
我们项目都是按照业务分库分表来设计的,对于一些数据量较大的表我们也进行了分表处理的,但是像流水和日志这种数据量还是很大的
283.说一下你们课程搜索的那个业务方法的大致逻辑
首先在课程上线的同时就会将课程信息放入es中,然后在用户搜索时就会接收到关键词,对其进行高亮、排序、分页处理再返回前端
284.项目并发高处理过不过来怎么办
1.我们可以使用分布式架构或者集群分散流量
2.可以使用rabbitMQ做异步响应
3.可以用Hystrix限流,但是要设置好熔断降级策略
285.讲一下你们的微服务授权方案 你还知道有哪些方案吗?
我们使用的是SpringSecurity+OAuth2.0+JWT来实现的,认证服务器颁发token,然后资源服务器负责认证和授权,其他的方案还有像单点登录和分布式会话,但是单点登录只能访问一个服务,方位另一个服务时需要重新认证,而分布式会话对安全信息的储存要求较高,比较复杂所以我们没有采用这两种方案
286.讲一下你们微服务认证授权的整体流程
客户端访问资源服务器,资源服务器颁发token,然后客户端储存token,在每次方式时都携带token,资源服务器会验证token,通过后返回资源
287.你们为啥要用JWT
安全,节省性能,因为每次客户端在访问资源服务器时都需要调用认证服务器来认证,这是很消耗性能的,所以我们就打算将签名信息储存在客户端,这时就出现了另一个问题,将签名信息直接储存在客户端是非常不安全的,而JWT刚好可以解决这个问题,它可以用非对称加密算法对信息进行加密,所以我们就使用了JWT
288.Oauth2认证,如果Token过期了你们是怎么处理的
先通过axios拦截器检查token是否过期,判断一下如果返回401就说明过期了,那么就会从local Storage中获取refresh_token发送给后端,后端接收到refresh_token之后会拼接完整url再发送Http请求获取新的token返回给前端,前端接收新的token就会将过期的覆盖掉,再使用新的token发送
289.Oauth2认证,如果Token被盗了怎么办?
首先我们需要设置token的过期时间,然后我们可以给token加上用户的ip作为标识,如果短时间内ip频繁变动,那么就提醒用户
290.秒杀的整体流程详细说一下
我们是使用预减库存的方案来实现的,首先将秒杀的商品和库存以信号量的方式存入redis,然后用户点击秒杀,直接走redis秒杀商品,满足资格就直接减库存,同时预创订单,同时将订单号返回给前端,然后用户带着订单号下单,确认下单后再在预创订单中写入订单数据,然后同步库存,接着调用支付接口,通过支付回调确认订单状态
291.如果流量更高,比如:每秒10W请求,应该怎么处理
使用LVS+Nginx集群+下游服务集群,如果流量再大就是用CDN分流
292.说一下支付超时处理方案?延迟队列和死信队列是什么意思?
使用RabbitMQ延迟队列来实现,将信息放到设置了过期时间的队列中,然后过期了的信息放入死信队列中
延迟队列就是设置了过期时间的队列,死信队列就是存放过期时间的队列
293.整个秒杀流程你用到了哪些队列
下单一个队列,订单超时一个队列,支付结果一个队列
294.秒杀成功,返回给用户的数据是什么?
预创订单号,用户通过这个订单号来下单
295.你们怎么处理超卖
使用redisson分布式锁来实现,用信号量来保证不会超卖
296.如何提高接口的qps
1.集群
2.使用连接池
3.设置最大连接数
297.你们这个前后端分离项目是怎么部署的
前端使用Nginx部署,后端用Springboot自带的Tomcat部署,然后通过代理解决前后端域名不一的问题
298.前后端分离的好处处
1.专人干专事
2.各司其职,避免甩锅的问题
3.前后端解耦
4.分开部署,减轻服务器压力
299.你们用什么做项目代码管理的
Gitee
300.讲讲Git相对于SVN的区别
Git每个开发人员都有本地仓库,可以在自己的库提交代码,而SVN只有一个中央库,然后每个工程只会生成一个.git目录,SVN会在每个目录下都生成一个.svn目录
301.你们微服务项目怎么部署
Doker,然后用Jenkins做持续集成
302.讲几个Git的命令
克隆,提交,推送,拉取
303.Mysql主从解决什么问题,不能解决什么问题?
可以使用一主多从模式,主负责写,从负责读,然后分担查询的压力,但是写的压力还是没有得到解决,解决方案:多个主数据库
304.MySql主从复制原理?
是依据binlog来的,主数据库在写的时候会在binlog中记录,然后从数据库会开启一个IO线程和一个SQL线程,IO线程将binlog中的记录保存到中继日志,然后SQL线程再去执行中继线程中的sql
305.MySql主从配置步骤?
先安装主从数据库,主数据库在my.ini中配置从数据库使用的账号和权限,从数据库配置主数据库的连接信息即可
306.什么是垂直分表,垂直分库,水平分表,水平分库
垂直分表:当一个表中字段过多时,就可以把表中的字段按类型分表,比如商品表可以分为商品主表,商品详细表以及商品价格表
垂直分库:就是可以按照业务需求,将不同业务分为不同的库
水平分表:当表中数据行数太多时就可以水平分表,将数据每多少行分为一张表
水平分库:当水平分表之后我们就可以考虑将这些表分库,因为当一个库中表太多了也会影响性能
307.分库分表后会出现哪些问题?怎么解决
1.会产生分布式事务,此时就可以使用seata来解决
2.垂直分库分表的话可能导致在查询时会用到两个库的表,所以我们就可以使用多线程查询
3.水平分库分库的话可能导致不同的表出现重复id,此时可以使用雪花算法来保证id唯一性
308.你们公司使用的是什么技术来水平分表?还可以有什么技术?有什么区别?
我们用的是ShardingJDBC来实现的,因为它是开源的,而且读写分离,分库分表操作简单,像TDDL用起来就比较复杂而且部分内容还不是开源的,Mycat也是,用起来比较复杂
309.你们使用什么规则来分库分表的?还有哪些规则?
我们使用是用垂直分库将不同的业务分为不同库,然后用垂直分表将一个表中的字段按类型分表,这样会出现一个问题,当查询的时候可能会涉及两个库,此时我们可以使用多线程来查询,比如商品表就可以分为商品表,商品价格表和商品详情表,其他规则的话还包括水平分表和水平分库,水平分表就是如果一个表中数据行数过多,可以将其拆分为多张表,每张表中存放多少条数据,但是这样也有个问题,就是可能会出现主键重复,这时我们就可以用雪花算法来解决,然后是水平分库,水平分库就是在进行了水平分表之后如果一个库中表过多,这样也会影响性能
310.你从哪些方面去优化你的数据库?
从小到大,先从sql入手,尽量使用索引查询,然后在看表,比如在表中增加冗余字段,减少连表查询次数,还有像建立索引和按照查询频率给字段进行垂直分表,最后到库,可以考虑使用垂直分库,不同的业务使用不同的库,最后可以做数据库集群
311.Mysql的集群有哪些模式?
一主一从,一主多从,双主,环形多主(效率最高),级联同步(主服务器只直接连接一个从服务器,其他从服务器连接那个从服务器)
312.单机优化到极致了,可以怎么优化?
做集群,比如一主多从这种,读写分离
313.多机优化有哪些方式?
分表,主表,主从同步
314.解释一下分库分表的含义?
垂直分表:就是当表中字段过多时,就可以把表中的字段按照使用频率分为不同的表,比如商品表就可以分为商品表,商品详情表和商品价格表
垂直分库:按照业务分库,这时会出现一个问题,在查询时可能会涉及到两个库,我们可以用多线程来进行操作
水平分表:当表中的数据行数过多时就可以将其分为多个表,每个表中储存比如100w条数据,但是此时也会出现一个问题,不同表可能出现主键重复,这时我们就可以使用雪花算法来生成主键,保证唯一性
水平分库:当进行了水平分表后,如果一个库中表过多的话会让性能边低,所以此时我们就可以分库存表
315.水平分表有哪些分表规则?
可以按照时间分表,Hash值(就是分几张表就模几),还有就是id区间,但是要保证id唯一性,比如使用雪花算法
316.能简单说一下你怎么使用shardingjdbc做读写分离的嘛
导包,然后在配置文件中配置datasource、主从数据库连接信息和负载均衡
317.能简单说一下你怎么使用shardingjdbc做读分库分表的嘛
需要在配置文件中配置datasource,多个数据库就要配置多个datasource,然后是分库分表策略,最后还要配置公共表
318.你们用什么工具监控JVM
Jvisualvm
319.JVM类加载流程
记载:加载磁盘中的字节码文件
验证:检查字节码文件是否真的是一个字节码文件
准备:为static修饰的变量分配空间,然后为final修饰的变量赋值
解析:将java中的符号引用替换为内容中的直接引用,比如全限定类名
初始化:为相关变量赋值
320.JVM类加载器有几种类型,分别加载什么东西,用到什么设计模式?
启动类加载器:加载lib下的类
扩展类加载器:加载ext下的类
应用程序类加载器:加载classpath下的类
自定义类加载器
然后是用到了双亲委派模式,是一种保证类加载安全的策略,就是按照启动类,扩展类,应用程序类,最后是自定义类的顺序进行加载,当上一级加载到了之后就不会加载下一级,保证了加载器的优先级,这样做就是为了不让我们轻易覆盖系统功能
321.JVM组成,以及他们的作用
运行数据区:
线程共享:存放虚拟机加载的类、静态变量、常量等等,然后jdk8之后改为了元空间,使用本地内存
方法区:
堆:存放对象的
线程隔离:
虚拟机栈:对应java方法,存放了局部变量表、操作数栈和动态链接等等
本地方法栈:对应本地方法,其余作用跟虚拟机栈差不多
程序计数器:确认任务执行顺序
执行引擎:
GC:处理没用的变量
322.在JVM层面,一个线程是如何执行的
在线程执行时每个方法都会作为一个栈帧放在虚拟机栈中,方法调用结束就出栈,然后在方法调用的时候创建的变量在虚拟机栈中,而实例在堆内存中,栈中的变量指向堆。当方法出栈后,栈中的变量就会销毁,而堆中的实例等待GC清理
323.程序内存溢出了,如何定位问题出在哪儿?
可以将内存溢出的内存保存到日志中,然后用Jvisualvm来分析日志。
324.垃圾标记算法
引用计数算法:给每个变量添加一个计数器,当这个变量被引用的时候就+1,没被引用就设置为0,但是这个方法在数据相互依赖的情况下无法使用
gcRoots:选择一个对象作为gcRoot,然后会去连接每一个对象,当连接一个对象连接不上时就说明这个对象不可用
325.垃圾回收算法
标记清除,标记整理,复制以及分代
326.垃圾回收器有哪些
主要是分为
新生代:
单线程:serial
多线程:有两个,一个parnew,注重于停顿时间,另一个是Parallel Scavenge,更注重于吞吐量
老年代:
单线程:serial old
多线程:CMS,和parallel old
327.Minor GC和Full GC
Minor GC就是新生代的GC,Full GC是老年代的GC
328.JVM优化的目的是什么?
优化程序内存使用的大小,然后减少程序的停顿,增加性能
329.什么是事务
就是一组数据要么全部成功要么全部失败
330.事务的四大特性
原子性:一组数据要么全部成功要么全部失败
持久性:可以将数据持久化到硬盘上
隔离性:两个线程执行事务必须按照顺序来
一致性:就是任何数据写入到数据库都要遵守规则
331.InnoDB如何保证原子性和持久性的
原子性用undo log,持久性用redo log,然后数据开始修改的时候先把原数据保存到undo log,再把新数据保存到redo log,出现回滚就可以根据undo log进行回滚,出现系统崩溃就可以使用redo log进行恢复
332.事务并发问题有哪些
脏读:读到了别人还没提交的数据
幻读:两次查询读到的数据条数不一样
不可重复读:上次查询读到的数据不一样
333.事务隔离级别有哪些,分别能解决什么问题
读已提交:不能解决
读未提交:解决脏读
可重复读:解决幻读和脏读
串行化:能解决三种
334.MySql的InnoDB是如何保证原子性的
利用undo log实现的,就是在数据修改前先存到undo log中,然后一旦需要回滚就可以通过undo log中的数据回滚
335.MySql的InnoDB是如何保证持久性的
redo log,当任务提交前把新数据放到redo log中,系统崩溃了就可以用redo log恢复数据
336.说一下事务的执行流程(Undolog+Redolog)
先把修改前的值放到undo log,再把修改后的值放到redo log,最后将redo log 写入磁盘
337.解释一下事务并发丢失更新问题,·如何解决
分为回滚丢失和覆盖丢失。
回滚丢失:两个线程同时操作一条数据,此时有一条线程回滚了,然后导致另一条线程也回滚了,四种隔离级别都可以解决
覆盖丢失:两个线程同时操作一条数据,此时一条线程先提交了数据,然后另一条在提交的时候就会覆盖之前提交的数据,串行化可以解决
338.InnoDB事务隔离的实现原理是什么
读写锁:写操作每次只能有一个线程获取