分布式锁:
分布式锁是一种跨JVM的互斥机制来控制共享资源的访问(单机的synchroized解决的是单机的并发问题)
什么情况下使用分布式锁?
1:分布式系统下,一个方法在同一个时间只能被一个机器的一个线程执行
2:高可用,高性能的获取锁和释放锁
3:具备可重入的特性
4:具备锁失效机制,防止死锁
5:具备非阻塞锁特征,没有获取到锁直接返回获取锁失败
实现的三种方式:基于数据库实现分布锁,基于Zookeeper实现分布锁,基于Redis实现分布锁。
@Bean的作用域问题以及声明周期
作用域:
在默认情况下SpringBean的作用域是单例模式(实例唯一:任意时刻每个类的对象最多只有一个,对象创建出来后常驻内存,直到Spring将其销毁),非单例模式(通过getBean可以获取多个对象)
自动装配机制:@Autowired(对属性用于装配的),此外比如某个方法是交由spring管理的(通常是构造方法或者Bean注解的方法,如果声明了参数spring框架也会自动尝试去调用的如果参数为1个自动装配,如果多个则名称匹配进行装配)
生命周期:
1:实例化 2:属性赋值 3:初始化 4:销毁
Collection里面有什么?
List,Set,Queue都是实现了collection接口,collection实现的接口是Iterable接口
list:可以允许重复的对象,可以插入null,是一个有序容器,保持了每个元素的插入信息 ,输出的顺序也是其擦插入的顺序,常用的实现类有ArrayList,linkedList,和Vectory
set:不可重复集合,根据实现类的不同,set集合也有可能是有序的,常用实现类有:HashSet ,LinkedHashSet,TreeSet(输出引用得到中序遍历结果,底层调用的是TreeMap),TreeSet是一个根据compar()和compareTo()的定义进行排序的有序容器。
Map遍历:
实现类:
TreeMap:本质上就是红黑树,其实现为红黑树的实现,结果是依据key的升序排列结果,在toString中使用(中序遍历(左根右)获得结果)
LinkedHashMap:输出引用得到的是有序的结果集合
HashMap:数据结构为散列表,输出得到无序结果----非线程安全的散列表结构,其key和value允许为null,
HashTable:数据结构为散列表,输出得到无序结果----线程安全的,其key和value不允许为null
ConcurrentHashMap:----线程安全的,其key和value不允许为null
map和collection是在集合中并列存在的,map集合为双列,set集合为单列
map遍历没有直接取出元素的方法,而是先转成Set集合再通过迭代器获取元素
遍历方式有三种:entrySet遍历,foreach遍历,keySet遍历
JWT的优缺点
优点:无状态,可扩展性好,自身包含验证所需信息,使得后端不用存储Session信息
缺点:安全性,token无法主动失效,无法自动续期,性能(存储太多信息会造成传输负荷)
实现:组成部分分为Header(头,指定算法与当前数据类型)
payLoad(载荷,通常包含clamis自定义数据和过期时间)
signature(签名,由算法和密钥构成)
解析:在文件过滤器中使用Jwt.parser().setSignature(密钥),parseClaimsJws(jwt).getBody();
数据库去重
根据判断是否存在重复字段分组,使用Max或者Min得到唯一的id
情况1:在数据量不大的情况下去除单个表的重复,我们可以先查出这个表中所有不重复的数据(如身份证号),然后使用Not in进行查询,重复的数据直接删除
情况2:在数据量庞大的情况下,情况1必然会导致查询效率底下,我们可以采用临时表,,先找出所有不重复的数据,将数据存储在临时表中,清空原表,将临时表数据插入原表,删除临时表。
Linux的基本命令
/cp:复制 /bin:保存文件 /home:用户主目录 /cd:切换到指定目录 cd..:切换到上一级目录
/user:应用程序的文件 /dev:保存外部设备 /:根目录 mkdir:创建文件夹 |:管道符(前一个命令的结果作为后一个命令的参数)
MyBatis的缓存级别和持久化
mybaits存在两级缓存
使用缓存的目的就是减少与数据库的交互,进而减少开销,提高系统效率
一级缓存:基于sqlSession的缓存,也称为会话缓存(只有当且仅当是同一个mapper,同一个抽象方法,同样的参数值时有效)默认为一级缓存
二级缓存:默认全局开启,基于namespace缓存,也成为namespace缓存,返回的结果类型必须是实现serializable接口,如果使用了resultMap封装,则必须使用id节点来封装主键映射。
mybatis的持久化
实现有三种方式:
方式一:基于xml方式,可以没有接口,sql语句写在xml文件中
方式二:单纯的基于注解的方式,可以没有xml文件,sql语句写在dao层的注解中
方式三(最为灵活,也是最常用的):xml方式和注解方式相结合,sql语句写在xml文件中
SpringMvc执行流程
首先我们了解到springMVC有五大组件,分别为:
1:前端控制器(DespatcherServlet)负责任务分配
2:处理映射器(HandlerMapping)
3:处理器适配器(HandlerAdapter)
4:处理器(Handler)
5:视图解析器(ViewResource)
流程:
1:用户发送url到前端控制器,
2:前端控制器请求处理映射器处理并且接收处理映射器返回的处理器执行链
3:前端控制器请求处理适配器并接收处理适配器返回的ModelAndView
(注意:这个过程实际上是处理器适配器请求处理器处理并且接收处理器返回的响应)
4:接下来前端控制器会请求视图解析器将逻辑视图解析为物理视图并接收返回的视图view对象
5:前端控制器去渲染视图
SQL优化
如何查看sql执行计划
使用explain分析你的SQL执行计划 (结果分析)
id:查询的顺序从大到小,同id顺序执行
type:显示访问类型,依据type可以判断出此次查询是全表扫描还是索引扫描,通常来说不同的type类型的性能依次为:ALL<index(扫描了索引)<range<ref<eq_ref<const<system
key:表示当前查询实际上使用到的索引
key_len:查询索引使用到的索引字节数
rows:估算SQL要查找到结果集需要扫描的行数,可以非常直观的显示SQL的效率快慢,原则上说rows越小越好
select_type:表示查询的类型,常取的值有SIMPLE,PRIMERY(最外层查询)
基础SQL优化
1:如果查询字段为*,可以尝试替换为具体字段
2:如果未使用索引,可以尝试添加索引
3:是否使用了嵌套,如果使用了嵌套可以尝试更换为联查
4:判断索引是否失效(造成全表查询)(可能情况有:采用了not in(),is null,表达式操作,!=,前模糊查询等)
高级SQL优化
1:批量插入数据的性能提升(,分割):默认的SQL存在事务控制,导致每条都需要事务开启和提交,批量处理是一次事务开启和提交
2:批量删除优化(< >):避免同时删除或者修改过多的数据,导致cpu利用率过高,造成锁表。一次性删除大量数据可能会造成锁表,建议分批次删除
3:伪删除操作:删除与否只是一个标识,修改状态来表示是否删除,操作速度快
索引的创建和删除
创建索引:create index name on
删除索引:drop index name on
SQL的执行顺序
选择表>找连接条件>连接>条件过滤>分组>聚合函数>分组过滤>选择字段>去重>排序>分页
SpringCloud
五大核心组件:Erueka:(功能类似nacos,做注册中心)
Frign:使用动态代理的机制(基于动态代理机制根据注解和选择器拼接url路径发起请求)
Ribbon:实现负载均衡()
Hystrix:(熔断降级的框架)
zuul:网关
1:可以使用nacos来替代掉Erueka(Erueka会将服务注册到EruekaService中,EruekaClient可以反过来从Erueka中去拉去注册表,从而知道服务器在哪里,不同于nacos,nacos会主动通知消费者提示新功能的上下线,而Erueka需要主动去拉去注册表才会知道)
2:使用Dubbo来替代掉Frign和Ribbon。dubbo就是RPC的实现,内置四种负载均衡。
1:随机分配策略(默认的)生成随机数,在哪个服务器范围就让哪个服务器运行
2:权重平均分配:依据服务器的权重进行分配
优化:平滑加权算法
3:活跃度自动感知:记录每个服务器处理一次请求的时间,按时间比例分配任务
4:一致性hash算法:根据请求参数进行hash运算,以后每次相同参数都会访问固定服务器
3:使用sentinel来替代Hystrix:Hystrix发起请求是走Hystrix的线程池,不同服务走不同的线程池,实现不同服务的调度隔离,避免服务雪崩的问题
4:gateway来替代zuul:
为什么使用Nacos,Erueka和Nacos的区别?
部署方式的问题:Erueka是需要创建SpringBoot项目的,nacos直接下载jar包启动即可,此外naocs的实例划分更细,分临时实例和永久实例,心跳机制检测也更加频繁。Erueka会定期向注册中心发送心跳,如果短期没有发送心跳,直接剔除。而nacos的心跳机制为服务会每隔15s向nacos发送一个心跳包,这个心跳包包含当前服务的基本信息,Nacos收到这个心跳包之后如果发现服务尚未注册就会注册到注册中心,但是如果已经注册则表示该服务为健康服务,如果超过15s未接收到心跳包,就会将该服务标记为不健康,累计超过30s未接收到,如果未临时实例就会剔除,为永久实例则仍继续标记为不健康。
何为热启动?
springboot自定义某个组件类,实现ApplicationRunner接口即可。可以在开机启动的时候自动执行此类中的方法。
为什么常用ArrayList而不是LinkedList?
底层结构分析即可:(安全性问题)
首先ArrayList底层是数组实现,LinkedList(在jdk1.8之前为双向链表,但是在1.8之后为双向循环链表),二者的数据结构不同从而导致了性能的差异。ArrayList查找元素效能是非常高的,linkedList中若查找头/尾的元素性能非常高(顺序查询或者逆序查询),但是查找中间效率低下。ArrayList若在尾部添加增删元素,此时效能非常高,但是其他部位性能一般,而linkedlist首位增删性能高,其余位置增删性能也不高(因为需要先查询)。
事务的隔离级别
读未提交>读已提交>可重复读>可串行化
乐观锁和悲观锁的实现
乐观锁解决超卖问题(for update会影响性能)通过版本号实现
RabbitMQ在项目中怎么用?干什么用?怎么实现?
异步处理,削峰填谷,应用解耦。
解耦:下订单操作:扣减库存,生成订单,发短信
削峰:在并发量高的情况下可以降低下降低系统的负荷,提升系统执行效率。
Redis强化
淘汰策略
当Redis服务器繁忙的时候,有大量的信息需要保存,此时如果redis的内存全满,再往redis中存储数据的化只有淘汰掉老数据才能保存新的数据。
noeviction:返回错误**默认**
allkeys-random:随机删除 volatile-random:有过期时间的数据库中随机删除数据 volatile-ttl:删除剩余有效时间最少的数据
缓存穿透:我们的redis中不存在数据,同时数据库中也不存在数据。此时会造成缓存击穿,所带来的危害就是可能会导致数据库查询效率变慢,甚至于数据库服务器宕机。因此可以使用布隆过滤器进行处理(布隆过滤器并不是完全准确,只在布隆过滤器说不存在的时候才真的不存在)
缓存击穿:redis中不存在而数据库中存在,查询直接击穿redis到数据库。只需要我们在业务逻辑层添加补充到redis中的逻辑即可。
缓存雪崩:同一时间出现大量的击穿现象。可常见于大量的数据同一时间过期,因此可以将数据的有效期设为随机数,从而可以避免同一时间大量的数据过期。进而产生缓存雪崩
持久化:Redis是将数据保存在内存上的,因此当突发断电的情况下保存的信息就会丢失,如果我们从数据库进行查询的话,当数据量小的时候还可以接受,但是当数据量大的时候,此恢复数据就会变得非常缓慢。更有可能,redis中本身是存在新的数据的,在还未与数据库同步的时候如果断电就会产生很严重的后果。因此redis是支持将数据保存在磁盘上的。当发生断电的时候,Redis会有两种基本的回复策略:RDB(Redis Database Backup)数据库快照,AOF(Append Only File)将Redis运行过的所有的命令(日志)备份下来,只保存命令,不保存数据,此外也支持AOF rewrite 将一些已经删除的新增命令也从日志中移除,从而达到日志瘦身的目的。
@Autowired和@Resource的区别
@Autowired注解是由spring提供的,他可以对构造方法,成员变量,方法参数注入,根据对象的类型完成自动注入。
@Resource由JDK提供的,遵循JSR-250规范,支持对象类型的注入,也支持对象名称的注入
两者基本上没有什么区别。可以使用所有的java框架,
区别:
1:注解内部定义的参数类型不同@Autowried只包含了required的参数,默认为true,表示开启自动注入。@Resource包含7个参数最重要的两个为name和type
2:装配方式不同,@Autowired是按照type自动装配的 @Resource是按照name自动装配的(也可自己选择)
3:应用范围不同
4:装载顺序不同
建议使用:@Autowried,支持优先注入,可以允许bean不存在。