一、Java 基础
1.JDK 和 JRE 有什么区别?
JDK是开发环境,JRE是运行环境。
2.== 和 equals 的区别是什么?
== 对基础类型是值比较,对引用类型是引用比较
equals本质和==相同,只是可以被重写
3.两个对象的 hashCode()相同,则 equals()也一定为 true,对吗?
不一定
4.final 在 java 中有什么作用?
不可二次赋值
5.java 中的 Math.round(-1.5) 等于多少?
Math.round的算法是先+0.5在向下取整,所以为-1
6.String 属于基础的数据类型吗?
不属于,String实际是一个包含字符数组的对象
7.java 中操作字符串都有哪些类?它们之间有什么区别?
String
StringBuffer
StringBuilder
相同点:都是通过char[]存储
不同点:
String每次修改都需要重新创建对象,StringBuffer,StringBuilder创建时char[]默认长度为19,通过append进行添加,
添加时判断长度是否超出,超出即扩容。StringBuffer使用了synchronized,所以线程安全,StringBuilder线程不安全,但是效率高
8.String str="i"与 String str=new String(“i”)一样吗?
String str="i"内存分配在常量池,赋值时,常量池里已经有了,则直接从常量池里拿来用,而不是重新创建,new String()则不管是否已存在都会重新创建。
9.如何将字符串反转?
StringBuffer的reverse()方法,charAt()方法反转
10.String 类的常用方法都有那些?
String.join():字符串凭借
String.charAt():字符位置
String.index():字符下标
11.抽象类必须要有抽象方法吗?
不一定
12.普通类和抽象类有哪些区别?
抽象类可以有抽象方法
13.抽象类能使用 final 修饰吗?
不能
14.接口和抽象类有什么区别?
接口是行为的抽象,抽象类是对象的抽象
15.java 中 IO 流分为几种?
InputStream,OutputStream,Reader,Writer
16.BIO、NIO、AIO 有什么区别?
BIO阻塞IO,可以通过多线程实现伪异步
NIO同步非阻塞IO,通过缓冲区实现块状数据读取,所以性能上优于BIO,IO完成时通知线程的方式,实现异步
AIO不了解
17.Files的常用方法都有哪些?
二、容器
18.java 容器都有哪些?
List,Map,Set
19.Collection 和 Collections 有什么区别?
Collection是集合,Collections是工具类
20.List、Set、Map 之间的区别是什么?
List有序集合
Set无序集合
Map映射表
21.HashMap 和 Hashtable 有什么区别?
HashMap线程不安全,并发put时,遇到hash冲突,相同的hash会存储为一个链表,并发时可能导致相同的key同时存入链表
Hashtable线程安全
22.如何决定使用 HashMap 还是 TreeMap?
需要排序用treeMap,无需排序用hashmap
23.说一下 HashMap 的实现原理?
hashMap通过桶加链表或红黑树实现,通过key值确定桶位置,hash冲突时在桶上添加链表
24.说一下 HashSet 的实现原理?
hashSet是基于HashMap实现的,添加的值其实是存在HashMap的key中
25.ArrayList 和 LinkedList 的区别是什么?
ArrayList基于数组,添加时存在扩容情况,性能较LinkedList较慢。
LinkedList读取数据只能从头或者尾遍历查询,性能较ArrayList较慢。
26.如何实现数组和 List 之间的转换?
List.toArray();遍历数据添加
27.ArrayList 和 Vector 的区别是什么?
Vector线程安全
28.Array 和 ArrayList 有何区别?
Array是数组,ArrayList是动态数组
29.在 Queue 中 poll()和 remove()有什么区别?
poll()和remove()都将移除并且返回对头,但是在poll()在队列为空时返回null,而remove()会抛出NoSuchElementException异常。
30.哪些集合类是线程安全的?
hashTable,ConcurrentHashMap,Vector,Stack
31.迭代器 Iterator 是什么?
用于遍历集合,可以删除结合节点,每个集合都需要实现自己的Iterator
32.Iterator 怎么使用?有什么特点?
33.Iterator 和 ListIterator 有什么区别?
ListIterator 比 Iterator多方法,使用范围不同,Iterator可以迭代所有集合;ListIterator 只能用于List及其子类
34.怎么确保一个集合不能被修改?
Collections.unmodifiableMap,Collections.unmodifiableList等
三、多线程
35.并行和并发有什么区别?
并行是不同实体的多个事件,并发是一个实体的多个事件
36.线程和进程的区别?
进程是资源分配的最小单位,线程是CPU调度的最小单位
37.守护线程是什么?
专门用于服务其他的线程,如垃圾回收线程
38.创建线程有哪几种方式?
new Thread,实现 Runnable,线程池
39.说一下 runnable 和 callable 有什么区别?
一个有返回值一个没有返回值,且callable可以抛出异常
40.线程有哪些状态?
NEW:线程被创建出来了,但是还没有start()。
RUNNABLE:可运行状态,这个状态比较特殊,我在图中把这个状态拆分成了两部分:一部分是READY,顾名思义是准备状态,另一部分是RUNNING,即运行状态。
准备状态:只能说明你有资格运行,单只要调度程序没有调度到你,你就永远是准备状态。从图中可以看出,好几个状态都能切换到准备状态,至于切换的方法,我在下文详细给大家整理出来介绍。
运行状态:线程调度程序从可运行池中选择一个线程作为当前线程时线程所处的状态。这也是线程进入运行状态的唯一一种方式。说白了,就是线程跑起来了。
BLOCKED:阻塞状态是线程阻塞在进入synchronized关键字修饰的方法或代码块(获取锁)时的状态。
WAITING:等待状态的线程不会被分配 CPU 执行时间,它们要等待被显式地唤醒,否则会处于无限期等待的状态。
TIMED_WAITING:超时等待状态的线程不会被分配 CPU 执行时间,不过无须无限期等待被其他线程显示地唤醒,在达到一定时间后它们会自动唤醒。这是和上面的 WAITING 状态的区别。
TERMINATED:终止状态,顾名思义,线程执行结束了。
41.sleep() 和 wait() 有什么区别?
sleep: 进入TIMED_WAITING状态,睡眠一段时间,到点进入准备状态,不释放锁
wait: 进入WAITING状态,需要被显示的唤醒,否则一直等待,释放锁,一定要获得锁才有用
42.notify()和 notifyAll()有什么区别?
notify唤醒一个线程,notifyAll唤醒所有线程
43.线程的 run()和 start()有什么区别?
run只是一个普通方法,是线程启动后运行的方法
start是启动线程,运行run方法
44.创建线程池有哪几种方式?
通过Executors工具类创建,自己new 线程池
/**
*
* @param corePoolSize 核心线程数
* @param maximumPoolSize 最大线程数
* @param keepAliveTime 线程存活实现
* @param unit 时间单位
* @param workQueue 等待队列
* @param threadFactory 线程工程
* @param handler 拒绝策略 1、AbortPolicy:直接抛出异常。
* 2、CallerRunsPolicy:只用调用者所在线程来运行任务。
* 3、DiscardOldestPolicy:丢弃队列里最近的一个任务,并执行当前任务。
* 4、DiscardPolicy:不处理,丢弃掉。
* 5、也可以根据应用场景需要来实现RejectedExecutionHandler接口自定义策略。如记录日志或持久化不能处理的任务。
*/
public void ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime,
TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory,
RejectedExecutionHandler handler)
45.线程池都有哪些状态?
- RUNNING:线程池一旦被创建,就处于 RUNNING 状态,任务数为 0,能够接收新任务,对已排队的任务进行处理。
- SHUTDOWN:不接收新任务,但能处理已排队的任务。调用线程池的 shutdown() 方法,线程池由 RUNNING 转变为 SHUTDOWN 状态。
- STOP:不接收新任务,不处理已排队的任务,并且会中断正在处理的任务。调用线程池的 shutdownNow() 方法,线程池由(RUNNING 或 SHUTDOWN ) 转变为 STOP 状态。
- TIDYING:
SHUTDOWN 状态下,任务数为 0, 其他所有任务已终止,线程池会变为 TIDYING 状态,会执行 terminated() 方法。线程池中的 terminated() 方法是空实现,可以重写该方法进行相应的处理。
线程池在 SHUTDOWN 状态,任务队列为空且执行中任务为空,线程池就会由 SHUTDOWN 转变为 TIDYING 状态。
线程池在 STOP 状态,线程池中执行中任务为空时,就会由 STOP 转变为 TIDYING 状态。 - TERMINATED:线程池彻底终止。线程池在 TIDYING 状态执行完 terminated() 方法就会由 TIDYING 转变为 TERMINATED 状态。
46.线程池中 submit()和 execute()方法有什么区别?
submit()有返回值,可以接收callable
execute()没有返回值,只能接收runnable
47.在 java 程序中怎么保证多线程的运行安全?
JDK Atomic开头的原子类、synchronized、LOCK,可以解决原子性问题
synchronized、volatile、LOCK,可以解决可见性问题
Happens-Before 规则可以解决有序性问题
volatile前的变量被volatile后的代码可见
锁的解锁 Happens-Before 于后续对这个锁的加锁,且被锁保护的共享资源在进行写操作时对其他线程可见。
它是指主线程 A 启动子线程 B 后,子线程 B 能够看到主线程在启动子线程 B 前的操作
它是指主线程 A 等待子线程 B 完成(主线程 A 通过调用子线程 B 的 join() 方法实现),当子线程 B 完成后(主线程 A 中 join() 方法返回),主线程能够看到子线程的操作。当然所谓的“看到”,指的是对共享变量的操作
对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生
final 关键字
48.多线程锁的升级原理是什么?
无锁:即对象未加锁
偏向锁:当一个线程第二次获取锁时,则会对比对象头中的ThreadId,如果一致则直接获得锁,如果不一致则判断ThreadId对应线程是否活跃,如果不活跃则会设置对象为无锁状态,然后通过cas去竞争锁
轻量级锁:当线程竞争偏向锁失败,即会自旋通过cas持续竞争锁,有点是不存在上下文切换,缺点是容易导致cpu空耗
重量级锁:当轻量级锁自旋CAS达到一定次数,或多个线程竞争激烈时则升级为重量级锁
49.什么是死锁?
两个锁线程互相请求对方的资源
50.怎么防止死锁?
保证获取锁的顺序一致;加锁时限;死锁检测
51.ThreadLocal 是什么?有哪些使用场景?
是提供线程变量存储的代理类,通过get,set方法可以获取到线程独有的变量.
之所以说是代理类,是因为存储的数据并不是存在ThreadLocal中,而是存在Thread中。这种方式可以有效避免没存泄露,Thread结束后,不会因为被ThreadLocal引用而释放。
场景:数据库连接,session管理,日志打印
52.说一下 synchronized 底层实现原理?
同步代码快用monitorenter和monitorexit实现
同步方法用acc_synchronized标识实现
53.synchronized 和 volatile 的区别是什么?
synchronized可以解决可见性、有序性和原子性问题
volatile只能解决可见性、有序性问题
54.synchronized 和 Lock 有什么区别?
synchronized是关键字,不需要手动释放锁
Lock是一个类,提供了更多的方法,如获取是否获取到锁,需要手动释放锁
55.synchronized 和 ReentrantLock 区别是什么?
synchronized 竞争锁时会一直等待;ReentrantLock 可以尝试获取锁,并得到获取结果
synchronized 获取锁无法设置超时;ReentrantLock 可以设置获取锁的超时时间
synchronized 无法实现公平锁;ReentrantLock 可以满足公平锁,即先等待先获取到锁
synchronized 控制等待和唤醒需要结合加锁对象的 wait() 和 notify()、notifyAll();ReentrantLock 控制等待和唤醒需要结合 Condition 的 await() 和 signal()、signalAll() 方法
synchronized 是 JVM 层面实现的;ReentrantLock 是 JDK 代码层面实现
synchronized 在加锁代码块执行完或者出现异常,自动释放锁;ReentrantLock 不会自动释放锁,需要在 finally{} 代码块显示释放
补充一个相同点:都可以做到同一线程,同一把锁,可重入代码块。
56.说一下 atomic 的原理?
通过unsafe实现cas来确保结果的正确性,并发高是自旋次数增多,cpu消耗大,CAS+自旋适合使用在低并发有同步数据的应用场景
四、反射
57.什么是反射?
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性,这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制
58.什么是 java 序列化?什么情况下需要序列化?
序列化:将 Java 对象转换成字节流的过程。
反序列化:将字节流转换成 Java 对象的过程。
当 Java 对象需要在网络上传输 或者 持久化存储到文件中时,就需要对 Java 对象进行序列化处理。
序列化的实现:类实现 Serializable 接口,这个接口没有需要实现的方法。实现 Serializable 接口是为了告诉 jvm 这个类的对象可以被序列化。
注意事项:
某个类可以被序列化,则其子类也可以被序列化
声明为 static 和 transient 的成员变量,不能被序列化。static 成员变量是描述类级别的属性,transient 表示临时数据
反序列化读取序列化对象的顺序要保持一致
59.动态代理是什么?有哪些应用?
动态代理:在运行时,创建目标类,可以调用和扩展目标类的方法。
Java 中实现动态的方式:JDK 中的动态代理 和 Java类库 CGLib。
应用:spring aop,拦截器
60.怎么实现动态代理?
Java 中实现动态的方式:JDK 中的动态代理 和 Java类库 CGLib。
五、对象拷贝
61.为什么要使用克隆?
java 对象是应用传递,修改对象会导致调用方法时传入的对象改变,通过克隆获取一个对象的副本可以避免这种改变
62.如何实现对象克隆?
实现cloneable方法或者通过序列号反序列号
63.深拷贝和浅拷贝区别是什么?
深拷贝,拷贝所有东西
浅拷贝,只拷贝对象的属性,对象的对象不拷贝
六、Java Web
64.jsp 和 servlet 有什么区别?
65.jsp 有哪些内置对象?作用分别是什么?
66.说一下 jsp 的 4 种作用域?
67.session 和 cookie 有什么区别?
68.说一下 session 的工作原理?
69.如果客户端禁止 cookie 能实现 session 还能用吗?
70.spring mvc 和 struts 的区别是什么?
71.如何避免 sql 注入?
严格限制 Web 应用的数据库的操作权限,给连接数据库的用户提供满足需要的最低权限,最大限度的减少注入攻击对数据库的危害
校验参数的数据格式是否合法(可以使用正则或特殊字符的判断)
对进入数据库的特殊字符进行转义处理,或编码转换
预编译 SQL(Java 中使用 PreparedStatement),参数化查询方式,避免 SQL 拼接
发布前,利用工具进行 SQL 注入检测
报错信息不要包含 SQL 信息输出到 Web 页面
72.什么是 XSS 攻击,如何避免?
73.什么是 CSRF 攻击,如何避免?
七、异常
74.throw 和 throws 的区别?
throw在代码中,标识抛出一个异常
throws在方法上,标识可能会抛出某种类型的异常,需要调用者处理
75.final、finally、finalize 有什么区别?
final表示变量不可修改
finally与try一起使用,表示执行完try后必然执行finally中的代码
finalize是一个方法,在垃圾回收前调用,默认是一个空方法
76.try-catch-finally 中哪个部分可以省略?
catch,finally可省略其中之一
77.try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?
会
78.常见的异常类有哪些?
空指针,数组下标越界,ClassCastException(强制类型转换),NumberFormatException(字符串转数字),IOException,IllegalArgumentException
八、网络
79.http 响应码 301 和 302 代表的是什么?有什么区别?
80.forward 和 redirect 的区别?
81.简述 tcp 和 udp的区别?
82.tcp 为什么要三次握手,两次不行吗?为什么?
83.说一下 tcp 粘包是怎么产生的?
84.OSI 的七层模型都有哪些?
85.get 和 post 请求有哪些区别?
86.如何实现跨域?
87.说一下 JSONP 实现原理?
九、设计模式
88.说一下你熟悉的设计模式?
策略模式,将不同算法抽象出来。
89.简单工厂和抽象工厂有什么区别?
简单工厂把所有的产品逻辑都写在一个工厂里,不方便扩展
抽象工厂定义的是一系列的产品生产接口,通过实现不同产品族的工厂来生产不同的产品。便于扩展新的产品族,但想新增新的产品就需要修改所有已有的工厂实现。
十、Spring/Spring MVC
90.为什么要使用 spring?
1.方便解耦,便于开发(Spring就是一个大工厂,可以将所有对象的创建和依赖关系维护都交给spring管理)
2.spring支持aop编程(spring提供面向切面编程,可以很方便的实现对程序进行权限拦截和运行监控等功能)
3.声明式事务的支持(通过配置就完成对事务的支持,不需要手动编程)
4.方便程序的测试,spring 对junit4支持,可以通过注解方便的测试spring 程序
5.方便集成各种优秀的框架()
6.降低javaEE API的使用难度(Spring 对javaEE开发中非常难用的一些API 例如JDBC,javaMail,远程调用等,都提供了封装,是这些API应用难度大大降低)
91.解释一下什么是 aop?
面向切面编程,通过代理方式在调用方法时,可以加上统一的逻辑,也可以拦截调用
92.解释一下什么是 ioc?
对象的创建和管理交给spring容器
93.spring 有哪些主要模块?
Spring Core: 基础,可以说 Spring 其他所有的功能都需要依赖于该类库。主要提供 IOC 依赖注入功能。
**Spring Aspects ** : 该模块为与AspectJ的集成提供支持。
Spring AOP :提供了面向切面的编程实现。
Spring JDBC : Java数据库连接。
Spring JMS :Java消息服务。
Spring ORM : 用于支持Hibernate等ORM工具。
Spring Web : 为创建Web应用程序提供支持。
Spring Test : 提供了对 JUnit 和 TestNG 测试的支持。
94.spring 常用的注入方式有哪些?
@Autowired
@Resource
95.spring 中的 bean 是线程安全的吗?
默认单例bean不是线程安全的。
可以修改bean作用域做到线程安全
96.spring 支持几种 bean 的作用域?
singleton:单例模式,在整个Spring IoC容器中,使用 singleton 定义的 bean 只有一个实例
prototype:原型模式,每次通过容器的getbean方法获取 prototype 定义的 bean 时,都产生一个新的 bean 实例
request:对于每次 HTTP 请求,使用 request 定义的 bean 都将产生一个新实例,即每次 HTTP 请求将会产生不同的 bean 实例。
session:同一个 Session 共享一个 bean 实例。
global-session:同 session 作用域不同的是,所有的Session共享一个Bean实例。
97.spring 自动装配 bean 有哪些方式?
@bean
@Component
98.spring 事务实现方式有哪些?
显示编码
xml
事务声明
99.说一下 spring 的事务隔离?
oracle:读已提交(默认),串行,只读
mysql:读未提交,读已提交,可重复读(默认),串行
读未提交:可以读取其他事务未提交的数据
读已提交:只能读取其他事务已提交的数据
可重复读(默认):只能读取事务开始时的数据,其他事务如何修改都不影响
串行:所有事务串行执行
只读:只能读取到事务开始时的数据,且事务中不能delete,update,insert
脏读 | 不可重复读 | 幻读 | |
---|---|---|---|
Read UnCommitted(读未提交) | 事务A启动 事务B启动 事务B修改数据a为数据b 事务A读取数据b 事务B报错回滚 事务A出现脏读现象,读取的是b,实际为a | 事务A启动 事务B启动 事务A读取数据a 事务B修改数据a为数据b 事务A读取数据b 事务A第一次读取和第二次读取数据不同即为不可重复读 | 事务A启动 事务B启动 事务A查询表a有1跳数据 事务B在表a添加数据 事务A读取表a数据2条 出现幻读现象 |
Read Committed(读提交) | 无 | 事务A启动 事务B启动 事务A读取数据a 事务B修改数据a为数据b 事务B提交 事务A读取数据b 事务A第一次读取和第二次读取数据不同即为不可重复读 | 事务A启动 事务B启动 事务A查询表a有1条数据 事务B在表a添加数据 事务B提交 事务A读取表a数据2条 出现幻读现象 |
Repeatable Read(重复读) | 无 | 无 | 事务A启动 事务B启动 事务A查询表a有1条数据 事务B在表a添加数据 事务B提交 事务A读取表a数据1条 事务A更新表a查询时间数据 事务A再次查询表a此时查询得到数据为2条 出现幻读现象 |
Serializable(序列化) | 无 | 无 | 无 |
100.说一下 spring mvc 运行流程?
核心控制器捕获请求、查找Handler、执行Handler、选择ViewResolver,通过ViewResolver渲染视图并返回
-
用户向服务器发送请求,请求被 Spring 前端控制 Servelt DispatcherServlet 捕获(捕获)
-
DispatcherServlet对请求 URL进行解析,得到请求资源标识符(URI)。然后根据该 URI,调用 HandlerMapping获得该Handler配置的所有相关的对象(包括 Handler对象以及 Handler对象对应的拦截器),最后以 HandlerExecutionChain对象的形式返回;(查找 handler)
-
DispatcherServlet 根据获得的 Handler,选择一个合适的 HandlerAdapter。 提取Request 中的模型数据,填充 Handler 入参,开始执行 Handler(Controller), Handler执行完成后,向 DispatcherServlet 返回一个 ModelAndView 对象(执行 handler)
-
DispatcherServlet 根据返回的 ModelAndView,选择一个适合的 ViewResolver(必须是已经注册到 Spring 容器中的 ViewResolver) (选择 ViewResolver)
-
通过 ViewResolver 结合 Model 和 View,来渲染视图,DispatcherServlet 将渲染结果返回给客户端。(渲染返回)
101.spring mvc 有哪些组件?
同上
102.@RequestMapping 的作用是什么?
指定controller接收的请求
103.@Autowired 的作用是什么?
自动装配bean
十一、Spring Boot/Spring Cloud
104.什么是 spring boot?
主要是简化了spring的使用难度,降低了对配置文件的要求,使得开发人员能够更容易得上手
105.为什么要用 spring boot?
主要是简化了spring的使用难度,降低了对配置文件的要求,使得开发人员能够更容易得上手
106.spring boot 核心配置文件是什么?
application文件
107.spring boot 配置文件有哪几种类型?它们有什么区别?
properties,yaml
.yml 格式不支持 @PropertySource 注解导入配置
108.spring boot 有哪些方式可以实现热部署?
109.jpa 和 hibernate 有什么区别?
jpa是规范,hibernate是实现
110.什么是 spring cloud?
111.spring cloud 断路器的作用是什么?
112.spring cloud 的核心组件有哪些?
十二、Hibernate
113.为什么要使用 hibernate?
-
对JDBC访问数据库的代码做了封装,大大简化了数据访问层繁琐的重复性代码。
-
Hibernate是一个基于JDBC的主流持久化框架,是一个优秀的ORM实现。他很大程度的简化DAO层的编码工作
-
hibernate使用Java反射机制,而不是字节码增强程序来实现透明性。
-
hibernate的性能非常好,因为它是个轻量级框架。映射的灵活性很出色。它支持各种关系数据库,从一对一到多对多的各种复杂关系。
Hibernate优缺点
优点:
更加对象化:以对象化的思维操作数据库,我们只需要操作对象就可以了,开发更加对象化。
移植性:因为Hibernate做了持久层的封装,你就不知道数据库,你写的所有的代码都具有可复用性。
Hibernate是一个没有侵入性的框架,没有侵入性的框架我们称为轻量级框架。对比Struts的Action和ActionForm,都需要继承,离不开Struts。Hibernate不需要继承任何类,不需要实现任何接口。这样的对象叫POJO对象。测试更加方便,提高了效率。
缺点:
由于对持久层封装过于完整,导致开发人员无法对SQL进行优化,无法灵活使用JDBC的原生SQL,Hibernate封装了JDBC,所以没有JDBC直接访问数据库效率高。要使用数据库的特定优化机制的时候,不适合用Hibernate。
框架中使用ORM原则,导致配置过于复杂,一旦遇到大型项目,配置文件和内容是非常庞大的,另外DTO满天飞,性能和维护问题随之而来。
如果项目中各个表中关系复杂,表之间的关系很多,在很多地方把lazy都设置false,会导致数据查询和加载很慢,尤其是级联查询的时候。
Hibernate在批量数据处理时有弱势,对于批量的修改,删除,不适合用Hibernate,这也是ORM框架的弱点。
114.什么是 ORM 框架?
ORM是对象关系型映射
115.hibernate 中如何在控制台查看打印的 sql 语句?
spring.jpa.properties.hibernate.show_sql=true //控制台是否打印spring.jpa.properties.hibernate.format_sql=true //格式化sql语句spring.jpa.properties.hibernate.use_sql_comments=true //指出是什么操作生成了该语句
116.hibernate 有几种查询方式?
HQL: FROM 对象名称
HBC: hibernate接口查询
SQL:普通sql查询,违背了orm的意义
117.hibernate 实体类可以被定义为 final 吗?
实体类可以定义为 final 类,但这样的话就不能使用 hibernate 代理模式下的延迟关联提供性能了,所以不建议定义实体类为 final。
118.在 hibernate 中使用 Integer 和 int 做映射有什么区别?
Integer 类型为对象,它的值允许为 null,而 int 属于基础数据类型,值不能为 null。
119.hibernate 是如何工作的?
- 读取并解析配置文件。
- 读取并解析映射文件,创建 SessionFactory。
- 打开 Session。
- 创建事务。
- 进行持久化操作。
- 提交事务。
- 关闭 Session。
- 关闭 SessionFactory。
120.get()和 load()的区别?
- 数据查询时,没有 OID 指定的对象,get() 返回 null;load() 返回一个代理对象。
- load()支持延迟加载;get() 不支持延迟加载。
121.说一下 hibernate 的缓存机制?
hibernate 常用的缓存有一级缓存和二级缓存:
一级缓存:也叫 Session 缓存,只在 Session 作用范围内有效,不需要用户干涉,由 hibernate 自身维护,可以通过:evict(object)清除 object 的缓存;clear()清除一级缓存中的所有缓存;flush()刷出缓存;
二级缓存:应用级别的缓存,在所有 Session 中都有效,支持配置第三方的缓存,如:EhCache。
122.hibernate 对象有哪些状态?
- 临时/瞬时状态:直接 new 出来的对象,该对象还没被持久化(没保存在数据库中),不受 Session 管理。
- 持久化状态:当调用 Session 的 save/saveOrupdate/get/load/list 等方法的时候,对象就是持久化状态。
- 游离状态:Session 关闭之后对象就是游离状态。
123.在 hibernate 中 getCurrentSession 和 openSession 的区别是什么?
- getCurrentSession 会绑定当前线程,而 openSession 则不会。
- getCurrentSession 事务是 Spring 控制的,并且不需要手动关闭,而 openSession 需要我们自己手动开启和提交事务。
124.hibernate 实体类必须要有无参构造函数吗?为什么?
hibernate 中每个实体类必须提供一个无参构造函数,因为 hibernate 框架要使用 reflection api,通过调用 ClassnewInstance() 来创建实体类的实例,如果没有无参的构造函数就会抛出异常。
十三、Mybatis
125.mybatis 中 #{}和 ${}的区别是什么?
#{}是预编译处理,${}是字符替换。 在使用 #{}时,MyBatis 会将 SQL 中的#{}替换成“?”,配合 PreparedStatement 的 set 方法赋值,这样可以有效的防止 SQL 注入,保证程序的运行安全。
126.mybatis 有几种分页方式?
分页方式:逻辑分页和物理分页。
- 逻辑分页: 使用 MyBatis 自带的 RowBounds 进行分页,它是一次性查询很多数据,然后在数据中再进行检索。
- 物理分页: 自己手写 SQL 分页或使用分页插件 PageHelper,去数据库查询指定条数的分页数据的形式。
127.RowBounds 是一次性查询全部结果吗?为什么?
RowBounds 表面是在“所有”数据中检索数据,其实并非是一次性查询出所有数据,因为 MyBatis 是对 jdbc 的封装,在 jdbc 驱动中有一个 Fetch Size 的配置,它规定了每次最多从数据库查询多少条数据,假如你要查询更多数据,它会在你执行 next()的时候,去查询更多的数据。就好比你去自动取款机取 10000 元,但取款机每次最多能取 2500 元,所以你要取 4 次才能把钱取完。只是对于 jdbc 来说,当你调用 next()的时候会自动帮你完成查询工作。这样做的好处可以有效的防止内存溢出。
128.mybatis 逻辑分页和物理分页的区别是什么?
逻辑分页:一次去除很多数据,在通过游标分页(RowBounds )
物理分页:通过limit或者rownum 取出需要的数据好处是效率高,不好的地方就是不同数据库有不同的搞法。
自己手写 SQL 分页或使用分页插件 PageHelper,去数据库查询指定条数的分页数据的形式。
129.mybatis 是否支持延迟加载?延迟加载的原理是什么?
什么是延迟加载?
- 延迟加载的条件:resultMap可以实现高级映射(使用association、collection实现一对一及一对多映射),association、collection具备延迟加载功能。
- 延迟加载的好处:
先从单表查询、需要时再从关联表去关联查询,大大提高 数据库性能,因为查询单表要比关联查询多张表速度要快。 - 延迟加载的实例:
如果查询订单并且关联查询用户信息。如果先查询订单信息即可满足要求,当我们需要查询用户信息时再查询用户信息。把对用户信息的按需去查询就是延迟加载。
Mybatis仅支持association关联对象和collection关联集合对象的延迟加载,association指的就是一对一,collection指的就是一对多查询。在Mybatis配置文件中,可以配置是否启用延迟加载lazyLoadingEnabled=true|false。
它的原理是,使用CGLIB创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用a.getB().getName(),拦截器invoke()方法发现a.getB()是null值,那么就会单独发送事先保存好的查询关联B对象的sql,把B查询上来,然后调用a.setB(b),于是a的对象b属性就有值了,接着完成a.getB().getName()方法的调用。这就是延迟加载的基本原理。
当然了,不光是Mybatis,几乎所有的包括Hibernate,支持延迟加载的原理都是一样的。
130.说一下 mybatis 的一级缓存和二级缓存?
- 一级缓存:基于 PerpetualCache 的 HashMap 本地缓存,它的声明周期是和 SQLSession 一致的,有多个 SQLSession 或者分布式的环境中数据库操作,可能会出现脏数据。当 Session flush 或 close 之后,该 Session 中的所有 Cache 就将清空,默认一级缓存是开启的。
- 二级缓存:也是基于 PerpetualCache 的 HashMap 本地缓存,不同在于其存储作用域为 Mapper 级别的,如果多个SQLSession之间需要共享缓存,则需要使用到二级缓存,并且二级缓存可自定义存储源,如 Ehcache。默认不打开二级缓存,要开启二级缓存,使用二级缓存属性类需要实现 Serializable 序列化接口(可用来保存对象的状态)。
131.mybatis 和 hibernate 的区别有哪些?
- 灵活性:MyBatis 更加灵活,自己可以写 SQL 语句,使用起来比较方便。
- 可移植性:MyBatis 有很多自己写的 SQL,因为每个数据库的 SQL 可以不相同,所以可移植性比较差。
- 学习和使用门槛:MyBatis 入门比较简单,使用门槛也更低。
- 二级缓存:hibernate 拥有更好的二级缓存,它的二级缓存可以自行更换为第三方的二级缓存。
- 对于性能要求不太苛刻的系统,比如管理系统、ERP 等推荐使用Hibernate;而对于性能要求高、响应快、灵活的系统则推荐使用MyBatis.
Hibernate与MyBatis对比
7.1 相同点
Hibernate与MyBatis都可以是通过SessionFactoryBuider由XML配置文件生成SessionFactory,然后由SessionFactory 生成Session,最后由Session来开启执行事务和SQL语句。
其中SessionFactoryBuider,SessionFactory,Session的生命周期都是差不多的。Hibernate和MyBatis都支持JDBC和JTA事务处理。
7.2 不同点
(1)hibernate是全自动,而mybatis是半自动
hibernate完全可以通过对象关系模型实现对数据库的操作,拥有完整的JavaBean对象与数据库的映射结构来自动生成sql。而mybatis仅有基本的字段映射,对象数据以及对象实际关系仍然需要通过手写sql来实现和管理。
(2)hibernate数据库移植性远大于mybatis
hibernate通过它强大的映射结构和hql语言,大大降低了对象与数据库(Oracle、MySQL等)的耦合性,而mybatis由于需要手写sql,因此与数据库的耦合性直接取决于程序员写sql的方法,如果sql不具通用性而用了很多某数据库特性的sql语句的话,移植性也会随之降低很多,成本很高。
(3)hibernate拥有完整的日志系统,mybatis则欠缺一些
hibernate日志系统非常健全,涉及广泛,包括:sql记录、关系异常、优化警告、缓存提示、脏数据警告等;而mybatis则除了基本记录功能外,功能薄弱很多。
(4)mybatis相比hibernate需要关心很多细节
hibernate配置要比mybatis复杂的多,学习成本也比mybatis高。但也正因为mybatis使用简单,才导致它要比hibernate关心很多技术细节。mybatis由于不用考虑很多细节,开发模式上与传统jdbc区别很小,因此很容易上手并开发项目,但忽略细节会导致项目前期bug较多,因而开发出相对稳定的软件很慢,而开发出软件却很快。hibernate则正好与之相反。但是如果使用hibernate很熟练的话,实际上开发效率丝毫不差于甚至超越mybatis。
(5)sql直接优化上,mybatis要比hibernate方便很多
由于mybatis的sql都是写在xml里,因此优化sql比hibernate方便很多。而hibernate的sql很多都是自动生成的,无法直接维护sql;虽有hql,但功能还是不及sql强大,见到报表等变态需求时,hql也歇菜,也就是说hql是有局限的;hibernate虽然也支持原生sql,但开发模式上却与orm不同,需要转换思维,因此使用上不是非常方便。总之写sql的灵活度上hibernate不及mybatis。
(6)缓存机制上,hibernate要比mybatis更好一些
MyBatis的二级缓存配置都是在每个具体的表-对象映射中进行详细配置,这样针对不同的表可以自定义不同的缓存机制。并且Mybatis可以在命名空间中共享相同的缓存配置和实例,通过Cache-ref来实现。
而Hibernate对查询对象有着良好的管理机制,用户无需关心SQL。所以在使用二级缓存时如果出现脏数据,系统会报出错误并提示。
总结:
(1)两者相同点
Hibernate和Mybatis的二级缓存除了采用系统默认的缓存机制外,都可以通过实现你自己的缓存或为其他第三方缓存方案,创建适配器来完全覆盖缓存行为。
(2)两者不同点
Hibernate的二级缓存配置在SessionFactory生成的配置文件中进行详细配置,然后再在具体的表-对象映射中配置是那种缓存。而MyBatis在使用二级缓存时需要特别小心。如果不能完全确定数据更新操作的波及范围,避免Cache的盲目使用。否则,脏数据的出现会给系统的正常运行带来很大的隐患。
(3)举个形象的比喻
MyBatis:机械工具,使用方便,拿来就用,但工作还是要自己来作,不过工具是活的,怎么使由我决定。(小巧、方便、高效、简单、直接、半自动)
Hibernate:智能机器人,但研发它(学习、熟练度)的成本很高,工作都可以摆脱他了,但仅限于它能做的事。(强大、方便、高效、复杂、绕弯子、全自动)
132.mybatis 有哪些执行器(Executor)?
**SimpleExecutor:**每执行一次update或select,就开启一个Statement对象,用完立刻关闭Statement对象。
**ReuseExecutor(重复使用执行器):**执行update或select,以sql作为key查找Statement对象,存在就使用,不存在就创建,用完后,不关闭Statement对象,而是放置于Map内,供下一次使用。简言之,就是重复使用Statement对象。
**BatchExecutor(批处理执行器):**执行update(没有select,JDBC批处理不支持select),将所有sql都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存了多个Statement对象,每个Statement对象都是addBatch()完毕后,等待逐一执行executeBatch()批处理。与JDBC批处理相同。
作用范围:Executor的这些特点,都严格限制在SqlSession生命周期范围内。
Mybatis中如何指定使用哪一种Executor执行器?
答:在Mybatis配置文件中,可以指定默认的ExecutorType执行器类型,也可以手动给DefaultSqlSessionFactory的创建SqlSession的方法传递ExecutorType类型参数。
133.mybatis 分页插件的实现原理是什么?
分页插件的基本原理是使用Mybatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,然后重写sql,根据dialect方言,添加对应的物理分页语句和物理分页参数。
举例:select * from student,拦截sql后重写为:select t.* from (select * from student)t limit 0,10
134.mybatis 如何编写一个自定义插件?
实现Interceptor接口,通过@Intercepts注解配置拦截的类和方法
十四、RabbitMQ
135.rabbitmq 的使用场景有哪些?
解耦,削峰,异步
136.rabbitmq 有哪些重要的角色?
生产者,消费者,代理
137.rabbitmq 有哪些重要的组件?
ConnectionFactory(连接管理器):应用程序与RabbitMQ之间建立连接的管理器
Channel(信道):消息推送使用的通道
Exchange(交换器):用于接受、分配消息
Queue(队列):用于存储生产者的消息
RoutingKey(路由键):生产者将消息发送给交换器的时候,会指定一个RoutingKey,用来指定这个消息的路由规则,这个RoutingKey需要与交换器类型和绑定键(BindingKey)联合使用才能最终生效。
BindKey(绑定键):用于把交换器的消息绑定到队列上
138.rabbitmq 中 vhost 的作用是什么?
相当于rabbitmq的虚拟机,避免队列和交换器的命名冲突,每个vhost只能访问自己的交换机、队列、绑定等。
139.rabbitmq 的消息是怎么发送的?
生产者把生产的消息通过channel发送到Exchange上,Exchange通过绑定的router key来选择Queue,消费者监听到Queue上有新的消息,就消费调此消息;
140.rabbitmq 怎么保证消息的稳定性?
1.消息持久化
2.ACK确认机制
3.设置集群镜像模式
4.消息补偿机制
141.rabbitmq 怎么避免消息丢失?
1.消息持久化
2.ACK确认机制
3.设置集群镜像模式
4.消息补偿机制
142.要保证消息持久化成功的条件有哪些?
exchange持久化
queue持久化
消息持久化发送
143.rabbitmq 持久化有什么缺点?
持久化的缺地就是降低了服务器的吞吐量,因为使用的是磁盘而非内存存储,从而降低了吞吐量。可尽量使用 ssd 硬盘来缓解吞吐量的问题。
144.rabbitmq 有几种广播类型?
- direct(默认模式):发送方把消息发送给订阅方,如果有多个订阅者,默认采取轮询的方式进行消息发送
- headers:与direct类似,但是性能差,基本不用
- fanout:分发模式,将消息发送给所有订阅者
- topic:匹配订阅模式,使用正则匹配到消息队列,能匹配到的都能接收到
145.rabbitmq 怎么实现延迟消息队列?
创建一个没有消费者的队列,设置超时时间,死信exchange和死信routkey,超时消息进入死信队列,消费者消费死信队列消息
146.rabbitmq 集群有什么用?
高可用:某个服务器出现问题,整个 RabbitMQ 还可以继续使用;
高容量:集群可以承载更多的消息量。
147.rabbitmq 节点的类型有哪些?
磁盘节点:消息会存储到磁盘。
内存节点:消息都存储在内存中,重启服务器消息丢失,性能高于磁盘类型。
148.rabbitmq 集群搭建需要注意哪些问题?
.erlang.cookie相同
端口要开放
要有一个磁盘节点
加入集群前,加入的一方先rabbitmqctl stop_app,加入成功后再start_app
149.rabbitmq 每个节点是其他节点的完整拷贝吗?为什么?
存储空间的考虑:如果每个节点都拥有所有队列的完全拷贝,这样新增节点不但没有新增存储空间,反而增加了更多的冗余数据;
性能的考虑:如果每条消息都需要完整拷贝到每一个集群节点,那新增节点并没有提升处理消息的能力,最多是保持和单节点相同的性能甚至是更糟。
150.rabbitmq 集群中唯一一个磁盘节点崩溃了会发生什么情况?
如果唯一磁盘的磁盘节点崩溃,不能进行一下操作:
- 不能创建队列
- 不能创建交换器
- 不能创建绑定
- 不能添加用户
- 不能更改权限
- 不能添加和删除集群节点
唯一磁盘节点崩溃了,集群是可以保持运行的,但你不能更改任何东西。
151.rabbitmq 对集群节点停止顺序有要求吗?
RabbitMq 对集群的停止的顺序是有要求的,应该先关闭内存节点,最后关闭磁盘节点。如果顺序恰好相反的话,可能造成消息的丢失。
十五、Kafka
152.kafka 可以脱离 zookeeper 单独使用吗?为什么?
kafka 不能脱离 zookeeper 单独使用,
因为 kafka 使用 zookeeper 管理和协调 kafka 的节点服务器。
153.kafka 有几种数据保留的策略?
1、按照过期时间保留
2、按照存储的消息大小保留
154.kafka 同时设置了 7 天和 10G 清除数据,到第五天的时候消息达到了 10G,这个时候 kafka 将如何处理?
这个时候 kafka 会执行数据清除工作,时间和大小不论那个满足条件,都会清空数据。
155.什么情况会导致 kafka 运行变慢?
1、cpu 性能瓶颈
如果CPU User非常高,需要查看消耗在哪个进程,可以用top(linux)命令看出,接着用top –H –p 看哪个线程消耗资源高,如果是java应用,就可以用jstack看出此线程正在执行的堆栈,看资源消耗在哪个方法上,查看源代码就知道问题所在;
如果CPU Sys非常高,可以用strace(linux)看系统调用的资源消耗及时间;
如果CPU Wait非常高,考虑磁盘读写,可以通过减少日志输出、异步或换速度快的硬盘。
2、磁盘读写瓶颈
磁盘I/O一个最显著的指标是繁忙率,可以通过减少日志输出、异步或换速度快的硬盘。
3、网络瓶颈
网络I/O主要考虑传输内容大小,不能超过硬件网络传输的最大值70%,可以通过压缩、减少内容大小、在本地设置缓存以及分多次传输等。
集群的数量不是越多越好,最好不要超过 7 个,因为节点越多,消息复制需要的时间就越长,整个群组的吞吐量就越低。
156.使用 kafka 集群需要注意什么?
十六、Zookeeper
157.zookeeper 是什么?
ZooKeeper致力于为分布式应用提供一个高性能、高可用,且具有严格顺序访问控制能力的分布式协调服务
158.zookeeper 都有哪些功能?
统一命名服务(naming)
配置管理
集群管理
分布式锁
159.zookeeper 有几种部署模式?
单机模式、伪集群模式、集群模式
160.zookeeper 怎么保证主从节点的状态同步?
Zookeeper的核心是原子广播,这个机制保证了各个Server之间的同步。实现这个机制的协议叫做Zab协议。Zab协议有两种模式,它们分别是恢复模式(选主)和广播模式(同步)。
恢复模式:当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server完成了和leader的状态同步以后,恢复模式就结束了。
因此,选主得到的leader保证了同步状态的进行,状态同步又保证了leader和Server具有相同的系统状态,当leader失去主权后可以在其他follower中选主新的leader。
161.集群中为什么要有主节点?
在分布式环境中,有些业务逻辑只需要集群中的某一台机器进行执行,
其他的机器可以共享这个结果,这样可以大大减少重复计算,提高性能,所以就需要主节点。
162.集群中有 3 台服务器,其中一个节点宕机,这个时候 zookeeper 还可以使用吗?
可以,只要有大于一半的节点可以,整个集群就可以提供服务
163.说一下 zookeeper 的通知机制?
客户端端会对某个 znode 建立一个 watcher 事件,当该 znode 发生变化时,这些客户端会收到 zookeeper 的通知,然后客户端可以根据 znode 变化来做出业务上的改变。
watcher的特点:
- 轻量级:一个callback函数。
- 异步性:不会block正常的读写请求。
- 主动推送:Watch被触发时,由Zookeeper服务端主动将更新推送给客户端。
- 一次性:数据变化时,Watch只会被触发一次。如果客户端想得到后续更新的通知,必须要在 Watch 被触发后重新注册一个 Watch。
- 仅通知:仅通知变更类型,不附带变更后的结果。
- 顺序性:如果多个更新触发了多个Watch,那 Watch 被触发的顺序与更新顺序一致。
使用watch的注意事项:
- 由于watcher是一次性的,所以需要自己去实现永久watch
- 如果被watch的节点频繁更新,会出现“丢数据”的情况
- watcher数量过多会导致性能下降
十七、MySql
164.数据库的三范式是什么?
第一范式(确保每列保持原子性)
第二范式(确保表中的每列都和主键相关)
第三范式(确保每列都和主键列直接相关,而不是间接相关)
165.一张自增表里面总共有 7 条数据,删除了最后 2 条数据,重启 mysql 数据库,又插入了一条数据,此时 id 是几?
一般情况下,我们创建的表的类型是InnoDB,如果新增一条记录(不重启mysql的情况下),这条记录的id是8;但是如果重启(文中提到的)MySQL的话,这条记录的ID是6。因为InnoDB表只把自增主键的最大ID记录到内存中,所以重启数据库或者对表OPTIMIZE操作,都会使最大ID丢失。
但是,如果我们使用表的类型是MylSAM,那么这条记录的ID就是8。因为MylSAM表会把自增主键的最大ID记录到数据文件里面,重启MYSQL后,自增主键的最大ID也不会丢失。
注:如果在这7条记录里面删除的是中间的几个记录(比如删除的是3,4两条记录),重启MySQL数据库后,insert一条记录后,ID都是8。因为内存或者数据库文件存储都是自增主键最大ID
166.如何获取当前数据库版本?
使用 select version() 获取当前 MySQL 数据库版本。
167.说一下 ACID 是什么?
指数据库事务,主要包括以下几项:
Atomicity(原子性):一个事务(transaction)中的所有操作,或者全部完成,或者全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被恢复(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。即,事务不可分割、不可约简。
Consistency(一致性):在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设约束、触发器、级联回滚等。
Isolation(隔离性):数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
Durability(持久性):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
168.char 和 varchar 的区别是什么?
字符应该是最常见的一种了,但似乎各个数据库都有所不同,比如oracle中就有啥varchar2之类。不过mysql似乎最多的还是集中在char和varchar上。
说说区别。char是固定长度的,而varchar会根据具体的长度来使用存储空间。比如char(255)和varchar(255),在存储字符串"hello world"的时候,char会用一块255的空间放那个11个字符,而varchar就不会用255个,他先计算长度后只用11个再加上计算的到字符串长度信息,一般1-2个byte来,这样varchar在存储不确定长度的时候会大大减少存储空间。
如此看来varchar比char聪明多了,那char有用武之地吗?还是很不少优势的。
一,存储很短的信息,比如门牌号码101,201……这样很短的信息应该用char,因为varchar还要占个byte用于存储信息长度,本来打算节约存储的现在得不偿失。
二,固定长度的。比如使用uuid作为主键,那用char应该更合适。因为他固定长度,varchar动态根据长度的特性就消失了,而且还要占个长度信息。
三,十分频繁改变的column。因为varchar每次存储都要有额外的计算,得到长度等工作,如果一个非常频繁改变的,那就要有很多的精力用于计算,而这些对于char来说是不需要的。
还有一个关于varchar的问题是,varchar他既然可以自动适应存储空间,那我varchar(8)和varchar(255)存储应该都是一样的,那每次表设计的时候往大的方向去好了,免得以后不够用麻烦。这个思路对吗?答案是否定的。mysql会把表信息放到内存中(查询第一次后,就缓存住了,linux下很明显,但windows下似乎没有,不知道为啥),这时内存的申请是按照固定长度来的,如果varchar很大就会有问题。所以还是应该按需索取
169.float 和 double 的区别是什么?
double 和 float 彼此的区别:
在内存中占有的字节数不同, 单精度内存占4个字节, 双精度内存占8个字节
有效数字位数不同(尾数) 单精度小数点后有效位数7位, 双精度小数点后有效位数16位
数值取值范围不同 根据IEEE标准来计算!
在程序中处理速度不同,一般来说,CPU处理单精度浮点数的速度比处理双精度浮点数快
double 和 float 彼此的优缺点:
float单精度
优点: float单精度在一些处理器上比double双精度更快而且只占用double双精度一半的空间
缺点: 但是当值很大或很小的时候,它将变得不精确。
double双精度
优点: double 跟 float比较, 必然是 double 精度高,尾数可以有 16 位,而 float 尾数精度只有 7 位
缺点: double 双精度是消耗内存的,并且是 float 单精度的两倍! ,double 的运算速度比 float 慢得多, 因为double 尾数比float 的尾数多, 所以计算起来必然是有开销的!
如何选择double 和 float 的使用场景!
首先: 能用单精度时不要用双精度 以省内存,加快运算速度!
float: 当然你需要小数部分并且对精度的要求不高时,选择float单精度浮点型比较好!
double: 因为小数位精度高的缘故,所以双精度用来进行高速数学计算、科学计算、卫星定位计算等处理器上双精度型实际上比单精度的快, 所以: 当你需要保持多次反复迭代的计算精确性时,或在操作值很大的数字时,双精度型是最好的选择。
说这么多其实就是小数点后面的保留位数多少的问题!
170.mysql 的内连接、左连接、右连接有什么区别?
1.内连接,显示两个表中有联系的所有数据;
2.左链接,以左表为参照,显示所有数据;
3.右链接,以右表为参照显示数据;
171.mysql 索引是怎么实现的?
数据结构:Hash、平衡二叉树、B树、B+树区别
https://www.cnblogs.com/toov5/p/10340349.html
172.怎么验证 mysql 的索引是否满足需求?
使用 explain 查看 SQL 是如何执行查询语句的,从而分析你的索引是否满足需求。
173.说一下数据库的事务隔离?
读未提交,读已提交,可重复读,串行
174.说一下 mysql 常用的引擎?
MySQL常用的四种引擎的介绍
(1):MyISAM存储引擎:不支持事务、也不支持外键,优势是访问速度快,对事务完整性没有 要求或者以select,insert为主的应用基本上可以用这个引擎来创建表
支持3种不同的存储格式,分别是:静态表;动态表;压缩表
静态表:表中的字段都是非变长字段,这样每个记录都是固定长度的,优点存储非常迅速,容易缓存,出现故障容易恢复;缺点是占用的空间通常比动态表多(因为存储时会按照列的宽度定义补足空格)ps:在取数据的时候,默认会把字段后面的空格去掉,如果不注意会把数据本身带的空格也会忽略。
动态表:记录不是固定长度的,这样存储的优点是占用的空间相对较少;缺点:频繁的更新、删除数据容易产生碎片,需要定期执行OPTIMIZE TABLE或者myisamchk-r命令来改善性能
压缩表:因为每个记录是被单独压缩的,所以只有非常小的访问开支
(2)InnoDB存储引擎*
该存储引擎提供了具有提交、回滚和崩溃恢复能力的事务安全。但是对比MyISAM引擎,写的处理效率会差一些,并且会占用更多的磁盘空间以保留数据和索引。
InnoDB存储引擎的特点:支持自动增长列,支持外键约束
(3):MEMORY存储引擎
Memory存储引擎使用存在于内存中的内容来创建表。每个memory表只实际对应一个磁盘文件,格式是.frm。memory类型的表访问非常的快,因为它的数据是放在内存中的,并且默认使用HASH索引,但是一旦服务关闭,表中的数据就会丢失掉。
MEMORY存储引擎的表可以选择使用BTREE索引或者HASH索引,两种不同类型的索引有其不同的使用范围
Hash索引优点:
Hash 索引结构的特殊性,其检索效率非常高,索引的检索可以一次定位,不像B-Tree 索引需要从根节点到枝节点,最后才能访问到页节点这样多次的IO访问,所以 Hash 索引的查询效率要远高于 B-Tree 索引。
Hash索引缺点: 那么不精确查找呢,也很明显,因为hash算法是基于等值计算的,所以对于“like”等范围查找hash索引无效,不支持;
Memory类型的存储引擎主要用于哪些内容变化不频繁的代码表,或者作为统计操作的中间结果表,便于高效地对中间结果进行分析并得到最终的统计结果,。对存储引擎为memory的表进行更新操作要谨慎,因为数据并没有实际写入到磁盘中,所以一定要对下次重新启动服务后如何获得这些修改后的数据有所考虑。
(4)MERGE存储引擎
Merge存储引擎是一组MyISAM表的组合,这些MyISAM表必须结构完全相同,merge表本身并没有数据,对merge类型的表可以进行查询,更新,删除操作,这些操作实际上是对内部的MyISAM表进行的。
175.说一下 mysql 的行锁和表锁?
InnoDB的行锁是针对索引加的锁,不是针对记录加的锁。并且该索引不能失效,否则都会从行锁升级为表锁。
行锁的劣势:开销大;加锁慢;会出现死锁
行锁的优势:锁的粒度小,发生锁冲突的概率低;处理并发的能力强
加锁的方式:自动加锁。对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁;对于普通SELECT语句,InnoDB不会加任何锁;当然我们也可以显示的加锁:
共享锁:select * from tableName where … + lock in share more
排他锁:select * from tableName where … + for update
InnoDB和MyISAM的最大不同点有两个:一,InnoDB支持事务(transaction);二,默认采用行级锁。加锁可以保证事务的一致性,可谓是有人(锁)的地方,就有江湖(事务);我们先简单了解一下事务知识。
176.说一下乐观锁和悲观锁?
悲观锁
总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程)。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。Java中synchronized和ReentrantLock等独占锁就是悲观锁思想的实现。
乐观锁
总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition机制,其实都是提供的乐观锁。在Java中java.util.concurrent.atomic包下面的原子变量类就是使用了乐观锁的一种实现方式CAS实现的。
177.mysql 问题排查都有哪些手段?
- 使用 show processlist 命令查看当前所有连接信息。
- 使用 explain 命令查询 SQL 语句执行计划。
- 开启慢查询日志,查看慢查询的 SQL。
178.如何做 mysql 的性能优化?
- 为搜索字段创建索引。
- 避免使用 select *,列出需要查询的字段。
- 垂直分割分表。
- 选择正确的存储引擎。
十八、Redis
179.redis 是什么?都有哪些使用场景?
redis是以一种基于内存运行并支持持久化的nosql数据库。
1、热点数据的缓存
由于redis访问速度块、支持的数据类型比较丰富,所以redis很适合用来存储热点数据,另外结合expire,我们可以设置过期时间然后再进行缓存更新操作,这个功能最为常见,我们几乎所有的项目都有所运用。
2、限时业务的运用
redis中可以使用expire命令设置一个键的生存时间,到时间后redis会删除它。利用这一特性可以运用在限时的优惠活动信息、手机验证码等业务场景。
3、计数器相关问题
redis由于incrby命令可以实现原子性的递增,所以可以运用于高并发的秒杀活动、分布式序列号的生成、具体业务还体现在比如限制一个手机号发多少条短信、一个接口一分钟限制多少请求、一个接口一天限制调用多少次等等。
4、排行榜相关问题
关系型数据库在排行榜方面查询速度普遍偏慢,所以可以借助redis的SortedSet进行热点数据的排序。
在奶茶活动中,我们需要展示各个部门的点赞排行榜, 所以我针对每个部门做了一个SortedSet,然后以用户的openid作为上面的username,以用户的点赞数作为上面的score, 然后针对每个用户做一个hash,通过zrangebyscore就可以按照点赞数获取排行榜,然后再根据username获取用户的hash信息,这个当时在实际运用中性能体验也蛮不错的。
5、分布式锁
这个主要利用redis的setnx命令进行,setnx:"set if not exists"就是如果不存在则成功设置缓存同时返回1,否则返回0 ,这个特性在俞你奔远方的后台中有所运用,因为我们服务器是集群的,定时任务可能在两台机器上都会运行,所以在定时任务中首先 通过setnx设置一个lock,如果成功设置则执行,如果没有成功设置,则表明该定时任务已执行。 当然结合具体业务,我们可以给这个lock加一个过期时间,比如说30分钟执行一次的定时任务,那么这个过期时间设置为小于30分钟的一个时间 就可以,这个与定时任务的周期以及定时任务执行消耗时间相关。
当然我们可以将这个特性运用于其他需要分布式锁的场景中,结合过期时间主要是防止死锁的出现。
6、延时操作
这个目前我做过相关测试,但是还没有运用到我们的实际项目中,下面我举个该特性的应用场景。 比如在订单生产后我们占用了库存,10分钟后去检验用户是够真正购买,如果没有购买将该单据设置无效,同时还原库存。 由于redis自2.8.0之后版本提供Keyspace Notifications功能,允许客户订阅Pub/Sub频道,以便以某种方式接收影响Redis数据集的事件。 所以我们对于上面的需求就可以用以下解决方案,我们在订单生产时,设置一个key,同时设置10分钟后过期, 我们在后台实现一个监听器,监听key的实效,监听到key失效时将后续逻辑加上。 当然我们也可以利用rabbitmq、activemq等消息中间件的延迟队列服务实现该需求。
7、分页、模糊搜索
redis的set集合中提供了一个zrangebylex方法,语法如下:
ZRANGEBYLEX key min max [LIMIT offset count]
通过ZRANGEBYLEX zset - + LIMIT 0 10 可以进行分页数据查询,其中- +表示获取全部数据
zrangebylex key min max 这个就可以返回字典区间的数据,利用这个特性可以进行模糊查询功能,这个也是目前我在redis中发现的唯一一个支持对存储内容进行模糊查询的特性。
前几天我通过这个特性,对学校数据进行了模拟测试,学校数据60万左右,响应时间在700ms左右,比mysql的like查询稍微快一点,但是由于它可以避免大量的数据库io操作,所以总体还是比直接mysql查询更利于系统的性能保障。
8、点赞、好友等相互关系的存储
Redis set对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的。 又或者在微博应用中,每个用户关注的人存在一个集合中,就很容易实现求两个人的共同好友功能。
这个在奶茶活动中有运用,就是利用set存储用户之间的点赞关联的,另外在点赞前判断是否点赞过就利用了sismember方法,当时这个接口的响应时间控制在10毫秒内,十分高效。
9、队列
由于redis有list push和list pop这样的命令,所以能够很方便的执行队列操作。
180.redis 有哪些功能?
-
数据缓存功能
-
分布式锁的功能
-
支持数据持久化
-
支持事务
-
支持消息队列
181.redis 和 memecache 有什么区别?
1、存储方式:
memecache 把数据全部存在内存之中,断电后会挂掉,数据不能超过内存大小
redis有部份存在硬盘上,这样能保证数据的持久性。
2、数据支持类型:
redis在数据支持上要比memecache多的多。
3、使用底层模型不同:
新版本的redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求。
4、运行环境不同:
redis目前官方只支持LINUX 上去行,从而省去了对于其它系统的支持,这样的话可以更好的把精力用于本系统 环境上的优化,虽然后来微软有一个小组为其写了补丁。但是没有放到主干上
182.redis 为什么是单线程的?
1.redis是基于内存的,内存的读写速度非常快;
2.redis是单线程的,省去了很多上下文切换线程的时间;
3.redis使用多路复用技术,可以处理并发的连接;
183.什么是缓存穿透?怎么解决?
请求在缓存层和数据层都取不到数据。通过缓存空值,和布隆过滤器来解决。
184.redis 支持的数据类型有哪些?
set,zset,hash,list,string
185.redis 支持的 java 客户端都有哪些?
Redisson、Jedis、lettuce 等等,官方推荐使用 Redisson。
186.jedis 和 redisson 有哪些区别?
Jedis 只是简单的封装了 Redis 的API库,Redisson 不仅封装了 redis ,还封装了对更多数据结构的支持,以及锁等功能
187.怎么保证缓存和数据库数据的一致性?
- 通过延迟双删来解决
- 通过消息队列保证删除缓存消息执行成功
188.redis 持久化有几种方式?
持久化的几种方式
Redis 持久化拥有以下三种方式:
- 快照方式(RDB, Redis DataBase)将某一个时刻的内存数据,以二进制的方式写入磁盘;
- 文件追加方式(AOF, Append Only File),记录所有的操作命令,并以文本的形式追加到文件中;
- 混合持久化方式,Redis 4.0 之后新增的方式,混合持久化是结合了 RDB 和 AOF 的优点,在写入的时候,先把当前的数据以 RDB 的形式写入文件的开头,再将后续的操作命令以 AOF 的格式存入文件,这样既能保证 Redis 重启时的速度,又能简单数据丢失的风险。
因为每种持久化方案,都有特定的使用场景,让我们先从 RDB 持久化说起吧
RDB 优缺点
1)RDB 优点
- RDB 的内容为二进制的数据,占用内存更小,更紧凑,更适合做为备份文件;
- RDB 对灾难恢复非常有用,它是一个紧凑的文件,可以更快的传输到远程服务器进行 Redis 服务恢复;
- RDB 可以更大程度的提高 Redis 的运行速度,因为每次持久化时 Redis 主进程都会 fork() 一个子进程,进行数据持久化到磁盘,Redis 主进程并不会执行磁盘 I/O 等操作;
- 与 AOF 格式的文件相比,RDB 文件可以更快的重启。
2)RDB 缺点
- 因为 RDB 只能保存某个时间间隔的数据,如果中途 Redis 服务被意外终止了,则会丢失一段时间内的 Redis 数据;
- RDB 需要经常 fork() 才能使用子进程将其持久化在磁盘上。如果数据集很大,fork() 可能很耗时,并且如果数据集很大且 CPU 性能不佳,则可能导致 Redis 停止为客户端服务几毫秒甚至一秒钟。
189.redis 怎么实现分布式锁?
通过set命令设置锁,设置key,value(用于确定锁的拥有者),nx,px
通过lua脚本来解锁,使用lua脚本判断锁的value是不是当前线程,防止误解锁,并且lua脚本来保证命令的原子性
190.redis 分布式锁有什么缺陷?
Redis 分布式锁不能解决超时的问题,分布式锁有一个超时时间,程序的执行如果超出了锁的超时时间就会出现问题。
191.redis 如何做内存优化?
192.redis 淘汰策略有哪些?
1)voltile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
2)volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
3)volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
4)allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
5)allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
6)no-enviction(驱逐):禁止驱逐数据
193.redis 常见的性能问题有哪些?该如何解决?
-
Master写内存快照,save命令调度rdbSave函数,会阻塞主线程的工作,当快照比较大时对性能影响是非常大的,会间断性暂停服务,所以Master最好不要写内存快照。
-
Master AOF持久化,如果不重写AOF文件,这个持久化方式对性能的影响是最小的,但是AOF文件会不断增大,AOF文件过大会影响Master重启的恢复速度。Master最好不要做任何持久化工作,包括内存快照和AOF日志文件,特别是不要启用内存快照做持久化,如果数据比较关键,某个Slave开启AOF备份数据,策略为每秒同步一次。
-
Master调用BGREWRITEAOF重写AOF文件,AOF在重写的时候会占大量的CPU和内存资源,导致服务load过高,出现短暂服务暂停现象。
-
Redis主从复制的性能问题,为了主从复制的速度和连接的稳定性,Slave和Master最好在同一个局域网内
十九、JVM
194.说一下 jvm 的主要组成部分?及其作用?
1.类加载器(Class Loader):加载类文件到内存。Class loader只管加载,只要符合文件结构就加载,至于能否运行,它不负责,那是有Exectution Engine 负责的。
2.执行引擎(Execution Engine):也叫解释器,负责解释命令,交由操作系统执行。
3.本地库接口(Native Interface):本地接口的作用是融合不同的语言为java所用
4.运行时数据区(Runtime Data Area):
195.说一下 jvm 运行时数据区?
堆:java对象存储区域
虚拟机栈:每个方法都会创建一个栈帧,用来存储局部变量表,操作数栈,动态链接,方法出口等信息。(线程私有)
本地方法栈:类似虚拟机栈,只是服务于native方法(线程私有)
程序计数器:指示Java虚拟机下一条需要执行的字节码指令。(线程私有)
方法区:用于存储已被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。
196.说一下堆栈的区别?
堆:存储java对象,对象使用结束需等待垃圾回收,非线程私有
栈:先进后出,每个方法都会创建一个栈帧,用来存储局部变量,方法出口,栈帧使用结束立即清理,线程私有
197.队列和栈是什么?有什么区别?
队列:先进先出
栈:先进后出
198.什么是双亲委派模型?
bootstrap classloader:最顶级的类加载器,加载lib下的类,核心类库
extension classloader:加载lib/ext目录下的类
app classloader:加载classpath目录下的类
双亲委派机制避免了同一种类型被重复加载。
可以自定义类加载器,加载指定目录下的类文件
199.说一下类加载的执行过程?
加载
简单来说,加载指的是把class字节码文件从各个来源通过类加载器装载入内存中。
验证
主要是为了保证加载进来的字节流符合虚拟机规范,不会造成安全错误。
包括对于文件格式的验证,比如常量中是否有不被支持的常量?文件中是否有不规范的或者附加的其他信息?
对于元数据的验证,比如该类是否继承了被final修饰的类?类中的字段,方法是否与父类冲突?是否出现了不合理的重载?
对于字节码的验证,保证程序语义的合理性,比如要保证类型转换的合理性。
对于符号引用的验证,比如校验符号引用中通过全限定名是否能够找到对应的类?校验符号引用中的访问性(private,public等)是否可被当前类访问?
准备
主要是为类变量(注意,不是实例变量)分配内存,并且赋予初值。
特别需要注意,初值,不是代码中具体写的初始化的值,而是Java虚拟机根据不同变量类型的默认初始值。
比如8种基本类型的初值,默认为0;引用类型的初值则为null;常量的初值即为代码中设置的值,final static tmp = 456, 那么该阶段tmp的初值就是456
解析
将常量池内的符号引用替换为直接引用的过程。
初始化
这个阶段主要是对类变量初始化,是执行类构造器的过程。
换句话说,只对static修饰的变量或语句进行初始化。
如果初始化一个类的时候,其父类尚未初始化,则优先初始化其父类。
如果同时包含多个静态变量和静态代码块,则按照自上而下的顺序依次执行。
200.怎么判断对象是否可以被回收?
可达性分析法
引用计数发
201.java 中都有哪些引用类型?
强引用:显示引用,new
软引用:内存不足时会被回收,可以考虑缓存使用
弱引用:每次垃圾回收时,不管是否内存足够都会被回收
虚引用:当只有虚引用时,对象会被加载到引用队列,但是对象不会被GC清楚,知道虚引用也被释放,对象才会被清楚,用于跟踪对象的GC回收的活动
202.说一下 jvm 有哪些垃圾回收算法?
复制清除法:新生代(需要有一片干净的缓存空间用于复制,默认8:1:1)
标记清楚法:老年代(容易产生内存碎片)
标记整理法:老年代(存在引用的迁移,需要更多的时间)
203.说一下 jvm 有哪些垃圾回收器?
cms:
G1:
204.详细介绍一下 CMS 垃圾回收器?
CMS(Concurrent Mark Sweep)收集器是一种以获得最短回收停顿时间为目标的收集器。从名字就能知道它是标记-清除算法的。但是它比一般的标记-清除算法要复杂一些,分为以下4个阶段:
- 初始标记:标记一下GC Roots能直接关联到的对象,会"Stop The World"。
- 并发标记:GC Roots Tracing,可以和用户线程并发执行。
- 重新标记:标记期间产生的对象存活的再次判断,修正对这些对象的标记,执行时间相对并发标记短,会“Stop The World”。
- 并发清除:清除对象,可以和用户线程并发执行。
205.新生代垃圾回收器和老生代垃圾回收器都有哪些?有什么区别?
新生代回收器:Serial、ParNew、Parallel Scavenge
老年代回收器:Serial Old、Parallel Old、CMS
整堆回收器:G1
新生代垃圾回收器一般采用的是复制算法,复制算法的优点是效率高,缺点是内存利用率低;老年代回收器一般采用的是标记-整理的算法进行垃圾回收。
206.简述分代垃圾回收器是怎么工作的?
分代回收器有两个分区:老生代和新生代,新生代默认的空间占比总空间的 1/3,老生代的默认占比是 2/3。 新生代使用的是复制算法,新生代里有 3 个分区:Eden、To Survivor、From Survivor,它们的默认占比是 8:1:1,
它的执行流程如下:
把 Eden + From Survivor 存活的对象放入 To Survivor 区;
清空 Eden 和 From Survivor 分区; From Survivor 和 To Survivor 分区交换,From Survivor 变 To Survivor,To Survivor 变 From Survivor。
每次在 From Survivor 到 To Survivor 移动时都存活的对象,年龄就 +1,当年龄到达 15(默认配置是 15)时,升级为老生代。大对象也会直接进入老生代。
老生代当空间占用到达某个值之后就会触发全局垃圾收回,一般使用标记整理的执行算法。
以上这些循环往复就构成了整个分代垃圾回收的整体执行流程。
207.说一下 jvm 调优的工具?
常用调优工具分为两类,jdk自带监控工具:jconsole和jvisualvm
208.常用的 jvm 调优的参数都有哪些?
- -Xms256m:初始化堆大小为 256m;
- -Xmx2g:堆最大内存为 2g;
- -Xmn50m:新生代的大小50m;
- -XX:+PrintGCDetails 打印 gc 详细信息
- -XX:+HeapDumpOnOutOfMemoryError 在发生OutOfMemoryError错误时,来dump堆快照
- -XX:NewRatio=4 设置年轻的和老年代的内存比例为 1:4;
- -XX:SurvivorRatio=8 设置新生代 Eden 和 Survivor 比例为 8:2;
- //参数上写的,都是新生代的垃圾回收器
- -XX:+UseSerialGC 新生代和老年代都用串行收集器 Serial + Serial Old
- -XX:+UseParNewGC 指定使用 ParNew + Serial Old 垃圾回收器组合;
- -XX:+UseParallelGC 新生代使用Parallel Scavenge,老年代使用Serial Old
- //参数上写的,都是老年代的垃圾回收器
- -XX:+UseParallelOldGC:新生代ParallelScavenge + 老年代ParallelOld组合;
- -XX:+UseConcMarkSweepGC:新生代使用ParNew,老年代的用CMS;
- -XX:NewSize;新生代最小值;
- -XX:MaxNewSize:新生代最大值
- -XX:MetaspaceSize 元空间初始化大小
- -XX:MaxMetaspaceSize 元空间最大值