最新面试题

word版下载地址 : 链接:https://pan.baidu.com/s/1STVlm2faLioHAM4bZRtuDw
提取码:18go

Java基础

HashMap 原理解析:

HashMap 调用put 方法步骤:
1.如果传入的hashMap是空,则重构hashMap
2.首先通过传入的key计算出HashCode,然后根据HashCode查找在数组中的位置。
2.1如果该位置未被占用,则直接将该键值插入,也就是找到bucket(桶)位置来存储Entry 对象。(这里是数组形式存储)
2.2发生hashCode位置存在Entry对象时 解决方法
2.2.1 使用equals比较key相同,直接新值替换旧值
2.2.2 若冲突位置已经是红黑树作为存储结构 则将该键值对插入红黑树中
2.2.3 冲突位置不为红黑树 将该节点插入链表
2.2.3.1 循环链表,循环到最后一个entry,插入新节点,如果链表内长度大于8将链表转化为红黑树 并将节点插入。若带插入数据与存储数据有重复时 结束
3.检查容量,若容量不足 则扩容

源码解析地址:https://blog.youkuaiyun.com/liuhaiquan123521/article/details/89349769

HashMap 为什么加入红黑树?

当链表长度大于8自动转为红黑树,因为链表对于检索效率比较低。所以加入红黑树数据结构实现高效检索。
红黑树相比avl树,在检索的时候效率其实差不多,都是通过平衡来二分查找。但对于插入删除等操作效率提高很多。红黑树不像avl树一样追求绝对的平衡,他允许局部很少的不完全平衡,这样对于效率影响不大,但省去了很多没有必要的调平衡操作,avl树调平衡有时候代价较大,所以效率不如红黑树,

参考:https://www.cnblogs.com/liwei2222/p/8013367.html

Java八大基本类型

在这里插入图片描述

Java的四种引用,强弱软虚,用到的场景

1.强引用:最普遍的一种引用方式,如String s = “abc”,变量s就是字符串“abc”的强引用,只要强引用存在,则垃圾回收器就不会回收这个对象。
2.软引用(SoftReference):用于描述还有用但非必须的对象,如果内存足够,不回收,如果内存不足,则回收。一般用于实现内存敏感的高速缓存,软引用可以和引用队列ReferenceQueue联合使用,如果软引用的对象被垃圾回收,JVM就会把这个软引用加入到与之关联的引用队列中。
3.弱引用(WeakReference)内存不管是否足够,都进行回收。回收之前加入与之关联的引用队列中
4.虚引用(PhantomReference)就是形同虚设。任何时候都被可能被回收

方法的重载和重写的区别

重写(override)
1、返回值、方法名和参数都相同。
2、子类异常不能超出父类异常
3、子类访问级别不能低于父类访问级别
方法重载(overloading):
重载是在同一个类中的两个或两个以上的方法,拥有相同的方法名,但是参数却不相同,方法体也不相同,最常见的重载的例子就是类的构造函数,可以参考API帮助文档看看类的构造方法

ArrayList、LinkedList、Vector的区别

ArrayList:底层数据结构是数组,查询快,增删慢。线程不安全,效率高
Vector:底层数据结构是数组,查询快,增删慢。线程安全,效率低。
Vector相对ArrayList查询慢(线程安全的)。
Vector相对LinkedList增删慢(数组结构)。
LinkedList:底层数据结构是链表,查询慢,增删快。线程不安全,效率高。

Vector和ArrayList的区别:
Vector是线程安全的,效率低。
ArrayList是线程不安全的,效率高。
共同点:底层数据结构都是数组实现的,查询快,增删慢。
ArrayList和LinkedList的区别:
ArrayList底层是数组结果,查询和修改快。
LinkedList底层是链表结构的,增和删比较快,查询和修改比较慢。
共同点:都是线程不安全的

队列(Queue)和堆栈(Stack)的区别及实现

区别:队列是有两个口,先进先出。栈是一个口。先进后出。
如何实现队列和堆栈:使用双向循环列表LinkedList实现。
Quene 可以调用LinkedList的addLast和removeFirst实现先进先出
Stack 可以调用LinkedList 的addFirst 和 removeFirst实现先进后出

什么是左移、右移、无符号右移?

左移:向左移动,低位补0.
右移:符号为正,高位补0;符号为负,高位补1
无符号右移:无论符号为正负,高位都补0

为什么没有无符号左移?

因为有无符号取决于高位是0还是1,也就是二进制第一位,而且左移是右边补位,不会影响高位,所以不会产生符号问题。
String、StringBuffer与StringBuilder的区别
String:频繁修改不适合String.因为String是final的,一旦创建不可修改。
StringBuffer:线程安全的,多线程使用
StringBuilder:线程不安全的。单线程使用,效率高

HashMap和HashTable的区别

HashMap是线程不安全的。允许有NULL值。是Map接口的实现类
HashTable是线程安全的。不允许NULL值。 Hashtable是基于陈旧的Dictionary类的

HashTable和ConcurrentHashMap的区别
ConcurrentHashMap仅仅锁定map的某个部分,而Hashtable则会锁定整个map。导致在并发量大的情况下ConcurrentHashMap性能优于HashTable
HashTable的迭代器是强一致性的,而concurrenthashmap是弱一致的。
(弱一致性是指当put进去key,value.然后马上通过key取出value可能在某段时间内还看不到这个元素)

多并发情况下HashMap是否还会产生死循环

HashMap 在并发执行 put 操作时会引起死循环,导致 CPU 利用率接近100%。因为多线程会导致 HashMap 的 Node 链表形成环形数据结构,一旦形成环形数据结构,Node 的 next 节点永远不为空,就会在获取 Node 时产生死循环。

foreach与正常for循环效率对比

需要循环数组结构的数据时,建议使用普通for循环,因为for循环采用下标访问,对于数组结构的数据来说,采用下标访问比较好。
需要循环链表结构的数据时,一定不要使用普通for循环,这种做法很糟糕,数据量大的时候有可能会导致系统崩溃。

NIO和传统的IO有什么区别呢?

IO是面向流的(一个字节一个字节的处理数据),阻塞的。适用于多连接、少数据量的。例如聊天服务器。
NIO是面向块(缓冲区)的,采取“预读”模式,他就会猜测你下一步可能会读取的数据而预先缓冲下来。非阻塞的。适用于少量连接,每次连接有大量数据的情况。 NIO的三大核心部分:Channel(通道),Buffer(缓冲区), Selector

XML 两种解析方式DOM 和 SAX 有什么区别

dom一次性把xml文件全部加载到内存中建立一个结构一模一样的树, 占据内存极大,效率低。可以随意修改xml文件
SAX解析器的优点是解析速度快,占用内存少,效率高。仅能够读取文件的内容,并不能修改内容

JDK 和 CGLib动态代理区别

1、JDK动态代理具体实现原理:
通过实现InvocationHandler接口创建自己的调用处理器;
通过为Proxy类指定ClassLoader对象和一组interface来创建动态代理;
通过反射机制获取动态代理类的构造函数,其唯一参数类型就是调用处理器接口类型;
通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数输入;
JDK动态代理是面向接口的代理模式,如果被代理目标没有接口那么Spring也无能为力,Spring通过Java的反射机制生产被代理接口的新的匿名实现类,重写了其中AOP的增强方法。
2、CGLib动态代理:
CGLib是一个强大、高性能的Code生产类库,可以实现运行期动态扩展java类,Spring在运行期间通过 CGlib继承要被动态代理的类,重写父类的方法,实现AOP面向切面编程呢。
3、两者对比:
JDK动态代理是面向接口的。
CGLib动态代理是通过字节码底层继承要代理类来实现(如果被代理类被final关键字所修饰,那么抱歉会失败)。
4、springAOP使用注意:
如果要被代理的对象是个实现类,那么Spring会使用JDK动态代理来完成操作(Spirng默认采用JDK动态代理实现机制);
如果要被代理的对象不是个实现类那么,Spring会强制使用CGLib来实现动态代理。
5.JDK和CGLib哪个块
对于单例的代理对象或者具有实例池的代理,因为无需频繁的创建代理对象,所以比较适合采用CGLib动态代理,反之,则比较适用JDK动态代理。(因为CGLib创建的动态代理对象比JDK创建的动态代理对象在运行的时候性能大概要高10倍。但是JDK创建对象所花费的时间要比CGLib创建对象所花费的时间少8倍左右)

泛型的作用以及泛型的擦除含义?

作用:1.类型的参数化,就是可以把类型像方法的参数那样传递。
2.泛型使编译器可以在编译期间对类型进行检查以提高类型安全,减少运行时由于对象类型不匹配引发的异常。
泛型擦除:Java 的泛型在编译器有效,在运行期被删除,也就是说所有泛型参数类型在编译后都会被清除掉

线程的集中创建方式?

Thread,实现Runnable或者Callable、使用Executor框架来创建线程池
Runnable和Callable的区别:
(1)Callable规定的方法是call(),Runnable规定的方法是run().
(2)Callable的任务执行后可返回值,而Runnable的任务是不能返回值的。
(3)call方法可以抛出异常,run方法不可以

Thread 类中的start() 和 run() 方法有什么区别?

start()方法被用来启动新创建的线程,而且start()内部调用了run()方法,这和直接调用run()方法的效果不一样。当你调用run()方法的时候,只会是在原来的线程中调用,没有新的线程启动,start()方法才会启动新线程。

线程池有哪几种?

newCachedThreadPool:创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
newFixedThreadPool:创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
newScheduledThreadPool:创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor:创建一个单线程化的线程池,它只会用唯一的工作线程串行来执行任务,如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它

Lock和synchronized区别

1、Synchronized 是关键字,Lock是一个Java类
2、Lock可以判断是否获取到锁,Synchronized 不能
3、Lock手动释放锁,Synchronized 自动释放锁
4、Lock锁适合大量同步的代码的同步问题,synchronized锁适合代码少量的同步问题

Java接口设计与性能优化方案?

设计原则:可读性、可维护性、可变更性
1.入参、出参、接口名做到命名规范,见名知意。
2.接口出参应包含调用接口信息,如错误编码和错误信息等。
3.保证接口功能单一,不要做大而全的接口,方便后期维护。
4.在代码中预知可能要发生的异常。
5.接口出参应该使用像json或者xml 这种与平台无关的数据格式。
6.对请求进行加密验证,保证请求安全。

性能优化:
1.对于经常用到且不易修改的数据进行redis缓存。
2.对于复杂的任务进行多线程异步处理。
3.对接口中设计到的sql进行调优处理。
4.尽量减少与数据库的连接次数。
5.减少代码中对对象的创建,尽量使用引用去操作对象。

Tomcat 性能优化(https://blog.youkuaiyun.com/u010195563/article/details/80966025)

1.修改内存等 JVM相关配置(在bin\catalina.sh 或 bin\catalina.bat 文件中修改)
Linux下修改TOMCAT_HOME/bin/catalina.sh,在其中加入,可以放在CLASSPATH=下面:
JAVA_OPTS="-server -XX:PermSize=512M -XX:MaxPermSize=1024m -Xms2048m -Xmx2048m"
-server:启用 JDK的 server 版本;
-Xms:Java虚拟机初始化时堆的最小内存,一般与 Xmx配置为相同值,这样的好处是GC不必再为扩展内存 空间而消耗性能;
-Xmx:Java虚拟机可使用堆的最大内存;
-XX:PermSize:Java虚拟机永久代大小;
-XX:MaxPermSize:Java虚拟机永久代大小最大值;

2.tomcat 线程优化

maxThreads=“600” //最大线程数
minSpareThreads=“100”//初始化时创建的线程数
maxSpareThreads=“500”//一旦创建的线程超过这个值,Tomcat就会关闭不再需要的socket线程。
acceptCount=“700”//指定当所有可以使用的处理请求的线程数都被使用时,可以放到处理队列中的请求数,超过这个数的请求将不予处理

3.修改Tomcat 的Connector
Tomcat支持三种接收请求的处理方式:BIO、NIO、APR 。(https://www.jianshu.com/p/751fe1524a4b)
Apr库提高Tomcat性能,提高并发量(从Tomcat 7.0.30版本开始,默认就是在Tomcat apr模式下运行。)
安装apr,参考https://blog.youkuaiyun.com/q386815991/article/details/79570123

配置参数参考https://blog.youkuaiyun.com/q386815991/article/details/79570123

SpringBean 的作用域?

singleton:单例模式在整个Spring IoC容器中,使用singleton定义的Bean将只有一个实例
prototype:多例模式,每次通过容器的getBean方法获取prototype定义的Bean时,都将产生一个新的Bean实例

request:对于每次HTTP请求,使用request定义的Bean都将产生一个新实例,即每次HTTP请求将会产生不同的Bean实例。只有在Web应用中使用Spring时,该作用域才有效
session:对于每次HTTP Session,使用session定义的Bean都将产生一个新实例。同样只有在Web应用中使用Spring时,该作用域才有效
globalsession:每个全局的HTTP Session,使用session定义的Bean都将产生一个新实例。典型情况下,仅在使用portlet context的时候有效。同样只有在Web应用中使用Spring时,该作用域才有效

如何解决跨域问题?

1.后台代码在被请求的Servlet中添加Header设置:response.setHeader(“Access-Control-Allow-Origin”, “域名”);
例如设置 Access-Control-Allow-Origin:,则允许所有域名的脚本访问该资源。
例如设置Access-Control-Allow-Origin:http://www.baidu.com,允许特定的域名访问。
跨域携带cookie 需要设置resp.setHeader(“Access-Control-Allow-Credentials”, “true”); // 允许客户端携带跨域cookie,此时Access-Control-Allow-Origin值不能为“
”,只能为指定单一域名 。
2.springBoot项目添加@CrossOrigin 注解
3.前端发送ajax时候设置dataType为jsonp类型。默认会把返回数据返回到success回调函数中。
原理:假设a网页调用b网站的服务
a网站会准备一个方法(回调函数),例如callme(args)
a网站在页面插入一个script标签,src指向b网站的地址,并带上callme作为参数
b网站处理后,把结果和回调方法的名字组成一个字符串返回,例如callme(‘ok’)
由于是script标签,所以字符串会被当成js解析执行,相当于调用到了callme方法
主要利用了script可以跨站点访问的特性,且只能用GET请求,需要服务端做点配合,并且需要信任服务器(安全考虑)。jquery的jsonp ajax只是封装了这个过程,让你看上去和普通ajax没什么区别,其实却一点关系都没有。

SQL

数据局表索引何时会失效

1,<>
2,like “%_” 百分号在前.
3,联合索引没有使用索引里非第一位置的索引列
4,字符型字段为数字时在where条件里不添加引号.
5,对索引列进行运算.需要建立函数索引.
6,not in ,not exist.
7,当变量采用的是times变量,而表的字段采用的是date变量时.或相反情况。
8. MySQL 4.1 以上版本的 IN 是走索引的, 但4.0及其以下版本是不走索引的。
9.or 会导致索引失效,如果or两边都使用索引,索引才会生效。
10.如果mysql估计使用全表扫描要比使用索引快,则不使用索引;

数据库索引的设计原则

1.避免对经常更新的表进行过多的索引,并且索引的列尽可能少。而对于经常查询的字段应该创建索引,但是避免添加不必要的字段。
2.数据量小的表不要使用索引,因为查询花费的时间可能比遍历索引的时间还要短。
3.在经常进行分组或者排序的字段上建立索引,排序的列是多个的时候,可以建立组合索引
4.对于某个字段的值很少的情况下不要添加索引。例如学生性别只有男和女。

Mysql索引的数据结构?(https://blog.youkuaiyun.com/kongmin_123/article/details/82055901)或(https://www.cnblogs.com/dongguacai/p/7241860.html)

B+Tree数据结构

B+Tree 相比 BTree 和二叉树来说,树结构更加“矮胖”,层数很少,从而避免了“瘦高”树结构。因为磁盘的IO次数和索引树的高度是相关的,所以层数越少的树结构效率越高。
B+Tree 相比 BTree 的优点:
1.单一节点存储更多的元素,使得查询的IO次数更少。因为B+Tree只有叶节点存放数据,其余节点用来索引,所以同样大小的磁盘页可以容纳更多的节点元素,而BTree是每个索引节点都会有Data域。这就意味着,数据量相同的情况下,B+Tree的结构比BTree更加“矮胖”,因此查询是IO次数也更少。这就决定了B+Tree更适合用来存储外部数据,也就是所谓的磁盘数据。
2.所有查询都要查找到叶子节点,查询性能稳定。B+Tree的查询必须最终查询到叶子节点,而B-Tree只要找到匹配元素即可,无论匹配元素处于中间节点还是叶子节点。因此,BTree的查询性能并不稳定(最好情况是只查根节点,最坏情况是查到叶子节点)。而B+Tree每一次查找都是稳定的。
3.所有叶子节点形成有序链表,便于范围查询。因为叶子节点用指针连在一起。

SQL关键字执行顺序(也可以是sql 的执行顺序)

FROM—>ON—>JOIN—>WHERE—>GROUP BY—>HAVING—>SELECT—>DISTINCT—>
ORDER BY—>LIMIT
1.找到表:from
2.拿着where指定的约束条件,去文件/表中取出一条条记录 (多表会执行on -->join)
3.将取出的一条条记录进行分组group by,如果没有group by,则整体作为一组
4.将分组的结果进行having过滤
5.执行select
6.去重
7.将结果按条件排序:order by
8.限制结果的显示条数

SQL优化的几种方法?

1.注意索引是否被使用,避免索引失效。
2.根据使用对查询结果字段进行输出,应尽量避免使用*号。
3.使用临时表缓存中间结果,避免程序多次扫描主表
4.通过explain 查看sql 的执行计划。
5.insert 插入时候对value 进行数据拼接。例如:
INSERT into person(name,age) values(‘A’,14),(‘B’,14),(‘C’,14),
6.在结果集没有重复数据的情况下,尽量使用尽量使用union all而不是union。因为union会进行去重和排序操作。
7.避免类型转换,对输入的参数进行控制,而不是在sql中对原有字段进行转化。
例如utime 是datetime类型,传入的参数是“2016-07-23”,在比较大小时通常是 date(utime)>“2016-07-23”,可以优化为utime>“2016-07-23 00:00:00”
8.子查询比主查询数据小的情况使用in(),子查询比主查询数据大的情况使用exists()。Exists先查询主表,in是先查询子表。
数据库事务特性(ACID)
原子性:事务中的操作要么都发生,要么都不发生。
一致性:如果事物执行之前数据库是一个完整的状态,那么事务结束后,无论事务是否执行成功,数据库任然是一个完整的状态。
隔离性:多个用户并发访问数据库时候,一个用户的事务不能被其他用户的事务所干扰,多个并发事务之间数据要相互隔离。
持久性:指一个事务一旦被提交,他对数据库的影响是永久性的。

Spring事务的传播行为和隔离级别

传播行为 及其意义
PROPAGATION_MANDATORY 表示该方法必须运行在一个事务中。如果当前没有事务正在发生,将抛出一个异常
PROPAGATION_NESTED 表示如果当前正有一个事务在进行中,则该方法应当运行在一个嵌套式事务中。被嵌套的事务可以独立于封装事务进行提交或回滚。如果封装事务不存在,行为就像PROPAGATION_REQUIRES一样。
PROPAGATION_NEVER 表示当前的方法不应该在一个事务中运行。如果一个事务正在进行,则会抛出一个异常。
PROPAGATION_NOT_SUPPORTED 表示该方法不应该在一个事务中运行。如果一个现有事务正在进行中,它将在该方法的运行期间被挂起。
PROPAGATION_SUPPORTS 表示当前方法不需要事务性上下文,但是如果有一个事务已经在运行的话,它也可以在这个事务里运行。
PROPAGATION_REQUIRES_NEW 表示当前方法必须在它自己的事务里运行。一个新的事务将被启动,而且如果有一个现有事务在运行的话,则将在这个方法运行期间被挂起。
PROPAGATION_REQUIRES 表示当前方法必须在一个事务中运行。如果一个现有事务正在进行中,该方法将在那个事务中运行,否则就要开始一个新事务。

隔离级别 及其含义
ISOLATION_DEFAULT 使用后端数据库默认的隔离级别。
ISOLATION_READ_UNCOMMITTED 允许读取尚未提交的更改。可能导致脏读、幻影读或不可重复读。
ISOLATION_READ_COMMITTED 允许从已经提交的并发事务读取。可防止脏读,但幻影读和不可重复读仍可能会发生。
ISOLATION_REPEATABLE_READ 对相同字段的多次读取的结果是一致的,除非数据被当前事务本身改变。可防止脏读和不可重复读,但幻影读仍可能发生。
ISOLATION_SERIALIZABLE 完全服从ACID的隔离级别,确保不发生脏读、不可重复读和幻影读。这在所有隔离级别中也是最慢的,因为它通常是通过完全锁定当前事务所涉及的数据表来完成的。

http协议

http请求包含哪几部分?

(参考https://www.cnblogs.com/ranyonsue/p/5984001.html)
1.请求行:URL字段和HTTP协议版本 例如:GET /index.html HTTP/1.1 请求方法有 GET、POST、HEAD、PUT、DELETE、OPTIONS、TRACE、CONNECT这几种
2.请求头(key value形式): User-Agent:产生请求的浏览器类型。
Accept:客户端可识别的内容类型列表。
Host:主机地址。
3.请求体: post方法中,会把数据以key value形式发送请求。
4.空行:发送回车符和换行符,通知服务器以下不再有请求头。

http响应包含哪几部分?

(参考https://www.cnblogs.com/ranyonsue/p/5984001.html)
1.状态行:由HTTP协议版本号, 状态码, 状态消息 三部分组成。
2.消息头:用来说明客户端要使用的一些附加信息
3.空行:消息报头后面的空行是必须的
4.响应正文:服务器返回给客户端的文本信息

HTTP之状态码

状态代码有三位数字组成,第一个数字定义了响应的类别,共分五种类别:
1xx:指示信息–表示请求已接收,继续处理
2xx:成功–表示请求已被成功接收、理解、接受
3xx:重定向–要完成请求必须进行更进一步的操作
4xx:客户端错误–请求有语法错误或请求无法实现
5xx:服务器端错误–服务器未能实现合法的请求

HTTP请求方法

根据HTTP标准,HTTP请求可以使用多种请求方法。
HTTP1.0定义了三种请求方法: GET, POST 和 HEAD方法。
HTTP1.1新增了五种请求方法:OPTIONS, PUT, DELETE, TRACE 和 CONNECT 方法。
GET 请求指定的页面信息,并返回实体主体。
HEAD 类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头
POST 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。
PUT 从客户端向服务器传送的数据取代指定的文档的内容。
DELETE 请求服务器删除指定的页面。
CONNECT HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。
OPTIONS 允许客户端查看服务器的性能。
TRACE 回显服务器收到的请求,主要用于测试或诊断。

RabbitMQ

RabbitMQ 的优缺点:

解耦:生产者发送消息到Mq服务器,所有消费者都到MQ中订阅消息,不需要关消息提供者是否存在。传统项目接口方式会造成系统耦合度很大,一个系统瘫痪,导致消息发送失败。
异步:生产者只需把消息发送到MQ服务器即可, 消费者从MQ服务器自行订阅消息进行消费。传统项目接口发送需要等待全部接口调用完毕才可返回,增加了请求的时间。
削峰:在系统高峰期可以进行限流,防止系统压力过大而导致崩溃。消息全部存储在队列正进行等待消费。

缺点也正是上面优点所带来的的问题,例如系统可用性降低,例如MQ服务器崩溃,导致消息无法发送出去。还有异步带来的数据一致性问题,ABC三个系统,假如AB消费成功,C消费失败,则会导致数据不一致。在系统的复杂度上也提升了一个数量级。对于这些缺点也有相应的解决办法进行解决。

RabbitMQ如何保证消息的可靠性传输(如何处理消息丢失的问题)?

生产者可以开启RabbitMq的事务机制(不推荐,吞吐量受影响) 或者 confirm模式(确认模式)。事务机制是同步的,confirm是异步的。

生产者将信道设置成confirm模式,一旦信道进入confirm模式,所有在该信道上面发布的消息都将会被指派一个唯一的ID(从1开始),一旦消息被投递到所有匹配的队列之后,broker就会发送一个确认给生产者(包含消息的唯一ID),这就使得生产者知道消息已经正确到达目的队列了,如果消息和队列是可持久化的,那么确认消息会在将消息写入磁盘之后发出,broker回传给生产者的确认消息中delivery-tag域包含了确认消息的序列号,此外broker也可以设置basic.ack的multiple域,表示到这个序列号之前的所有消息都已经得到了处理;
此处可以在监听器监听消息是否成功被投递到broker

channel.addConfirmListener(new ConfirmListener() {
   @Override  //监听被拒绝的消息
   public void handleNack(long deliveryTag, boolean multiple) throws IOException {
      System.err.println("-------no ack!-----------");
   }
   
   @Override  //监听被确认的消息
   public void handleAck(long deliveryTag, boolean multiple) throws IOException {
      System.err.println("-------ack!-----------");
   }

消费者开启消息手动签收确保消息成功被消费。通过channel.basicAck(envelope.getDeliveryTag(), false); 设置消息手动签收。

如何防止RabbitMQ弄丢数据?

持久化Quene,但是不会持久化Quene中的消息,在设置消息的delivery= 2持久化消息。

消费端如何防止消息丢失?

关闭消息的自动确认机制。当消息每次消费完在程序里面人工ack确认。

如何避免消息重复投递或重复消费?

消息生产时,MQ针对每个发送的消息都会内部生成一个唯一Id,作为去重的依据。

消息是基于什么传输的?

由于TCP连接的创建和销毁开销较大,且并发数受系统资源限制,会造成性能瓶颈。RabbitMQ使用信道的方式来传输数据。信道是建立在真实的TCP连接内的虚拟连接,且每条TCP连接上的信道数量没有限制。

消息是如何路由的?

消息发布到交换器时,消息将拥有一个路由键(routing key),通过该路由键找到相应的队列,把消息存储到队列中进等待消费。

不同交换器有不同的路由规则,常用的三种交换器如下:
fanout:如果交换器收到消息,将会广播到所有绑定的队列上
direct:如果路由键完全匹配,消息就被投递到相应的队列
topic:可以使来自不同源头的消息能够到达同一个队列。 使用topic交换器时,可以使用通配符(*,#)

springBoot

springBoot 的优点

1.独立运行:直接打成jar包运行,因为内嵌了各种servlet容器
2.简化配置:例如spring-boot-starter-web启动器自动依赖其他组件,简少了maven的配置
3.自动配置:提供了各种组件的启动器(starters)
4.无代码生成和XML配置:基于注解开发
5.应用监控:Spring Boot提供一系列端点可以监控服务及应用,做健康检测。

SpringBoot自动配置原理

在@SpringBootApplication中有一个注解@EnableAutoConfiguration。而这个注解也是一个派生注解,其中的关键功能由@Import提供,其导入的AutoConfigurationImportSelector类的selectImports()方法通过SpringFactoriesLoader.loadFactoryNames()扫描所有具有META-INF/spring.factories的jar包。spring-boot-autoconfigure-x.x.x.x.jar里就有一个这样的spring.factories文件。这个spring.factories文件也是一组一组的key=value的形式,其中一个key是EnableAutoConfiguration类的全类名,而它的value是一个xxxxAutoConfiguration的类名的列表,这些类名以逗号分隔。把这些类加载到容器中。这些类中有一些条件注解,当满足条件注解时候则会进行自动配置

Linux

查找进程和杀死进程。

1.ps 命令用于查看当前正在运行的进程。
grep 是搜索
例如: ps -ef | grep java
表示查看所有进程里 CMD 是 java 的进程信息
2、ps -aux | grep java
-aux 显示所有状态
3.根据端口号查找进程
直接使用 netstat -anp | grep portno
即:netstat –apn | grep 8080
4. kill 命令用于终止进程
例如: kill -9 [PID]
-9 表示强迫进程立即停止
通常用 ps 查看进程 PID ,用 kill 命令终止进程

Redis

Redis相比memcached有哪些优势?

(1) memcached所有的值均是简单的字符串,redis作为其替代者,支持更为丰富的数据类型
(2) redis的速度比memcached快很多
(3) redis可以持久化其数据

Redis支持哪几种数据类型以及使用场景?

Redis是以键值对存储数据的,key是String,value为以下几种类型
String:value支持String和数字。多用于常规计数,例如微博粉丝,点赞数。
List:实现为双向链表(FIFO)。例如可做为简单的消息队列使用。
Set:set 的内部实现是一个 value永远为null的HashMap,实际就是通过计算hash的方式来快速排重的,这也是set能提供判断一个成员是否在集合内的原因。和List 的功能类似,可以去重。提供判断某个成员是否存在与Set集合中,这是list不能支持的。在微博应用中,可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合。Redis可以非常方便的实现如共同关注、共同喜好、二度好友等功能。
Sorted Set:和set类似,但是Sorted Set 是有序不重复的。例如在直播系统中,实时排行信息包含直播间在线用户列表,各种礼物排行榜,弹幕消息(可以理解为按消息维度的消息排行榜)等信息
Hash:hash的成员(相当于hashMap中的key比较少时)比较少是,采用一维数组的方式来紧凑存储,当数据量增大时会自动转成hashmap结构。当用户存储结构化数据时候采用这种方式,例如存储用户信息对象数据等

redis集群是如何实现的?(也可叫做分区)

Redis 集群中内置了 16384个哈希槽,当需要在 Redis 集群中放置一个 key-value 时,redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点。如下图
在这里插入图片描述

Redis 集群如何增加分区(扩容)?

参考https://www.cnblogs.com/PatrickLiu/p/8473135.html
1.增加master节点
2.新增master节点加入集群
3.指定集群中某个master节点进行哈希槽分配到新节点上。

迁移数据逻辑
迁移工作,可以使用redis-trib管理软件进行迁移,具体原理如下:
1、对目标节点发送cluster setslot import 命令,使哈希槽处于import状态,让目标节点做好准备接收迁移准备。
2、对源节点发送cluster setslot migrating命令,使哈希槽处于MIGRATING状态,让源节点做好准备迁移准备。
3、对源节点,发送cluster getkeysinslot 命令,获取对应slot的最多count个属于slot的key名。
4、对于步骤3中获取的key,向源节点发送命令migrate <key_name> 0 命令,将被选中的键原子地从源节点迁移到目标节点。
5、重复上述3,4步骤,直到所有key都迁移成功

迁移期间访问问题
当在迁移过程中,如果被访问的slot,可能会有部分key存在在源节点,有部分在目标节点中。
1、当客户端发送请求到源节点的时候,源节点会查看对应的key是否还在本节点,如果存在,则直接执行命令返回给客户。如果不存在,则会给客户端返回一个ASK错误,指引客户端往正在导入的目标slot去请求对应的key。客户端可以通过返回的ASK错误中的目标节点进行对应KEY的请求。
2、当客户端发送请求到目标节点时。
1)如果客户端请求时,带上ASKING标识,由目标节点会执行对应KEY的查询。正常情况下,如果是通过查询源slot,获取ASK错误之后,再到目标节点进行查询的时候,需要带上ASKING标识。
2)如果客户端请求时,未带上ASKING标识,原由上,对应的slot还属于源节点,则目标节点会拒绝执行KEY查询,会返回一个MOVED错误给客户端,告诉客户端对应的KEY的slot属于源节点。正常情况下,如果第一次请求KEY到了正在迁移的目标节点,则会收到MOVED错误。

Redis常见性能问题和解决方案:

Master最好不要做任何持久化工作,如RDB内存快照和AOF日志文件
如果数据比较重要,某个Slave开启AOF备份数据,策略设置为每秒同步一次
为了主从复制的速度和连接的稳定性,Master和Slave最好在同一个局域网内
尽量避免在压力很大的主库上增加从库

Redis分区有什么缺点?

1.多个key通常不能被支持。例如两个set集合求交集,集合被存储到不同的节点上。
2.同时操作多个key,则不能使用Redis事务.
3.数据处理非常复杂

redis集群投票机制

redis集群中有多台redis服务器不可避免会有服务器挂掉。redis集群服务器之间通过互相的ping-pong判断是否节点可以连接上。如果有一半以上的节点去ping一个节点的时候没有回应,集群就认为这个节点宕机了。

Redis 为什么集群下最少有3个节点。

集群中节点的fail是通过集群中超过半数的节点检测失效时才生效,.例如只有两个节点,挂掉一个,剩下一个投票是不会超过50%的,所以最少要三个主节点,三个从节点。

Redis的并发竞争问题是如何解决的?

1.客户端角度,为保证每个客户端间正常有序与Redis进行通信,对连接进行池化,同时对客户端读写Redis操作采用内部锁synchronized。   2.服务器角度,利用setnx实现锁。

redis 中主从、哨兵和集群这三个有什么区别 ?

主从:master/slave 主redis写入数据会通过主从复制把两个从redis也写入数据,相当于备份。
哨兵:监控主从的健康情况,master宕机之后。把slave提升为master。
集群:数据分片。把16384个哈希槽分配到多个节点上。同时包括主从和哨兵的功能。

Redis 大量数据插入如何操作?(管道)

从Redis 2.6开始redis-cli支持一种新的被称之为pipe mode的新模式用于执行大量数据插入工作。cat data.txt | redis-cli --pipe (命令集文件 | 批量插入命令)
Java 程序代码:

jedis.select(0);
Pipeline pipeline = jedis.pipelined();
for(int i=0;i<10000;i++){ 
pipeline.set("p"+i, "p"+i);	
}
pipeline.sync();
jedis.close();

Pipe 适合 执行一些相互之间无关的命令或者不需要获取命令的返回值。反之则需要使用Redis Script Load 命令。
原理是只开启一次连接,把命令放到队列中去执行命令。性能提升的原因主要是TCP连接中减少了“交互往返”的时间。
pipeline期间将“独占”当前redis连接,此期间将不能进行非“管道”类型的其他操作,直到该pipeline关闭。

Redis 事务如何执行?

Multi 开启事务,然后把命令入队,并不马上执行,执行exec命令才执行入队的命令。如果是在入队时报错,那么都不会执行;在非入队时报错,那么成功的就会成功执行。放弃事务命令是discard。
redis同一个事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚。官方解释命令执行失败有可能是语法错误或者程序员操作bug,这种问题不会出现在生产环境,所以Redis选用更加简单和快速的方法,没有实现错误回滚的功能。
redis能保证A(原子性)和I(隔离性),D(持久性)看是否有配置RDB或者AOF持久化操作,但无法保证一致性,因为redis事务不支持回滚。

Redis 持久化方式?

RDB持久化(原理是将Reids在内存中的数据库记录定时dump到磁盘上的RDB持久化),相当于内存快照。
AOF(append only file)持久化(原理是将Reids的操作日志以追加的方式写入文件),相当于日志文件。

什么是缓存穿透,如何解决?

查询缓存和数据库中都都不存在的数据,每次都会到数据库进行查询,对数据库造成压力。
解决方法:即使数据库中不存在,也把该空值设置到缓存中,设定较短的缓存过期时间。

什么是缓存雪崩,如何解决?

大量缓存集中失效,在此时间内,对此批缓存进行集中访问,会对数据库造成较大压力。
解决方法:分散缓存过期时间,集中缓存的数据进行过期时间添加随机因子进行控制。但是例如redis服务节点宕机,这对数据库压力是不可预知的。

什么是缓存击穿,如何解决?

在大并发的情况下对某个热点key进行集中式访问,当这个key失效的瞬间,持续的大并发就击破缓存,直接请求数据库,对数据库造成很大压力。
解决方法:对于热点key 可以设置永不失效。

Redis有哪几种数据淘汰策略?

allkeys-lru: 尝试回收最少使用的键(LRU),使得新添加的数据有空间存放。
volatile-lru: 尝试回收最少使用的键(LRU),但仅限于在过期集合的键,使得新添加的数据有空间存放。
allkeys-random: 回收随机的键使得新添加的数据有空间存放。
volatile-random: 回收随机的键使得新添加的数据有空间存放,但仅限于在过期集合的键。
volatile-ttl: 回收在过期集合的键,并且优先回收存活时间(TTL)较短的键,使得新添加的数据有空间存放。
volatile和allkeys规定了是对已设置过期时间的数据集淘汰数据还是从全部数据集淘汰数据,后面的lru、ttl以及random是三种不同的淘汰策略,再加上一种no-enviction永不回收的策略。

Redis 默认提供了数据库,redis集群如何选择数据库。

默认提供了16个数据库,redis集群无法选择数据库,默认在0数据库上。

redis 查看集群中hash槽的分配情况的命令

切换到实例对应的bin目录下,然后连接到某个节点(./redis-cli -c -p 端口号)然后执行命令:cluster slots

Redis 查看集群中主从关系。

切换到实例对应的bin目录下,然后连接到某个节点(./redis-cli -c -p 端口号)然后执行命令:info replication

springBoot 使用reids 的几个常用注解。

@EnableCaching
当你在配置类(@Configuration)上使用@EnableCaching注解时,会触发一个post processor,这会扫描每一个spring bean,查看是否已经存在注解对应的缓存。如果找到了,就会自动创建一个代理拦截方法调用,使用缓存的bean执行处理。

@Cacheable(value = { “sampleCache” ,“sampleCache2”},key="#id")
当某个方法使用这个注解时候,会把数据缓存,当下次再次访问这个方法时候,则先去缓存中获取,没有数据再去数据库获取数据,然后进行缓存。Value指的是从哪个缓存中获取数据,key就是上面指定的#id,从缓存中获取key是id对应的值的数据。Key可以使用springEL表达式 和root对象。例如#id 就是查找key=id值的(springEL表达式)

@CachePut(“user”)
与Cacheable区别就是Cacheable先看缓存如果有,直接缓存换回,CachePut则是每次都会调用并且把返回值放到缓存

@CacheEvict(“user”)
删除缓存中的数据

Mybatis

#{}和${}的区别是什么?

#{}是预编译处理,$ {} 是字符串替换。
Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;
Mybatis在处理${}时,就是把 ${}替换成变量的值。
使用#{}可以有效的防止SQL注入,提高系统安全性

通常一个Xml映射文件,都会写一个Dao接口与之对应,请问,这个Dao接口的工作原理是什么?Dao接口里的方法,参数不同时,方法能重载吗?

Dao接口,就是人们常说的Mapper接口,接口的全限名,就是映射文件中的namespace的值,接口的方法名,就是映射文件中MappedStatement的id值,接口方法内的参数,就是传递给sql的参数。Mapper接口是没有实现类的,当调用接口方法时,接口全限名+方法名拼接字符串作为key值,可唯一定位一个MappedStatement,举例:com.mybatis3.mappers.StudentDao.findStudentById,可以唯一找到namespace为com.mybatis3.mappers.StudentDao下面id = findStudentById的MappedStatement。在Mybatis中,每一个 select、insert 、update、delete标签,都会被解析为一个MappedStatement对象。
Dao接口里的方法,是不能重载的,因为是全限名+方法名的保存和寻找策略。
Dao接口的工作原理是JDK动态代理,Mybatis运行时会使用JDK动态代理为Dao接口生成代理proxy对象,代理对象proxy会拦截接口方法,转而执行MappedStatement所代表的sql,然后将sql执行结果返回。

Mybatis不使用Dao接口可以进行数据库操作么?

可以。直接使用session调用session原生的api进行操作
例如 session.selectOne(‘key’,parameter); 这样namespace 和 id 可以随意命名。

Mybatis是如何进行分页的?分页插件的原理是什么?

Mybatis使用RowBounds对象进行分页,他是进行对查询出来的结果集进行分页,相当于在内存中进行分页,查询数据量大的时候不建议使用。
可以使用分页插件进行物理分页,分页插件的基本原理是使用Mybatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,然后重写sql,根据dialect方言,添加对应的物理分页语句和物理分页参数。

Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式?

1.使用标签,定义返回结果和接受对象属性名之间的映射关系。
2.使用别名,将列的别名书写为对象的属性名。
有了列名和属性名的关系后,mybatis通过反射创建对象,同时通过反射给对象的属性逐一赋值并返回。找不到映射关系的属性是无法赋值的。

Mybatis编程步骤

以流的方式加载mybatis配置文件
创建SqlSessionFactory
通过SqlSessionFactory创建SqlSession
通过sqlsession执行数据库操作
调用session.commit()提交事务
调用session.close()关闭会话

如何实现批量操作

1.在sql文件中使用进行sql拼接。适合少量插入。
2.使用ExecutorType.BATCH创建SqlSession(官方推荐),但是不能使用自增ID,原因事务未提交。例:SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
设置ExecutorType.BATCH原理:把SQL语句发个数据库,数据库预编译好,数据库等待需要运行的参数,接收到参数后一次运行,ExecutorType.BATCH只打印一次SQL语句,多次设置参数步骤,

使用MyBatis的mapper接口调用时有哪些要求?

Mapper接口方法名和mapper.xml中定义的每个sql的id相同;
Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql 的parameterType的类型相同;
Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同;
Mapper.xml文件中的namespace即是mapper接口的类路径。

Mybatis 的一级缓存和二级缓存

一级缓存是 SqlSession 级别的缓存

使用一级缓存的条件:默认mybatis 的一级缓存 是开启的。
1、同一个session中
2、相同的SQL和参数

sqlSession:使用一级缓存。
sqlSessionTemplate :不使用一级缓存,因为使用sqlSessionTemplate 每次执行sql 会获取新的sqlSession

二级缓存是 mapper 级别的缓存,多个 SqlSession 共享

查询中途出现插入、更新、删除的commit操作,二级缓存将被清空,在此执行相同mapper 文件下的sql 则进行sql 查询。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值