1.设计模式的7大原则
- 单一职责原则:一个类只有一个职责
- 接口隔离:一个接口只有一类职责
- 依赖倒转:高层模块不应该依赖低级模块,应该依赖他们的抽象或者实现(接口定义规范把细节留给他们的实现类)
代码案例:
-
public class DependencyInversion {
-
public static void main(String[] args) {
-
//客户端无需改变
-
Person person = new Person();
-
person.receive(new Email());
-
person.receive(new WeiXin());
-
}
-
}
-
//定义接口
-
interface IReceiver {
-
String getInfo();
-
}
-
class Email implements IReceiver {
-
public String getInfo() {
-
return "电子邮件信息: hello,world";
-
}
-
}
-
//增加微信
-
class WeiXin implements IReceiver {
-
public String getInfo() {
-
return "微信信息: hello,ok";
-
}
-
}
-
//方式 2
-
class Person {
-
//这里我们是对接口的依赖,而不是直接依赖实现类。
-
public void receive(IReceiver receiver) {
-
System.out.println(receiver.getInfo());
-
}
-
}
- 里氏替换:子类可以继承父类的扩展,但不要改变父类原有功能
- 开闭原则:对扩展开放,对修改关闭
- 迪米特法则:一个类对自已依赖的类知道越少越好
- 合成复用原则:多用合成和聚合方式,少用继承
扩展:类与类之间的关系
依赖(一个类用到了其他类)
泛化(继承)
实现
聚合(set注入)
组合(构造注入)
篇幅限制下面就只能给大家展示小册部分内容了。整理了一份核心面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题
需要全套面试笔记的【点击此处即可】即可免费获取
2.设计模式分类
- 创建型模式
创建型模式专注于对象的创建方式,包括单例模式、工厂方法模式、抽象工厂模式、建造者模式和原型模式。
- 单例模式:保证系统中只有一个对象实例,提供全局访问点。
- 工厂方法模式:定义一个用于创建对象的接口,交由子类决定实例化的类。
- 抽象工厂模式:提供一个创建相关或依赖对象的接口,而无需指定它们具体的类。
- 建造者模式:将一个复杂对象的构建与它的表示分离,使同样的构建过程可以创建不同的表示。
- 原型模式:通过复制现有的实例来创建新的对象,而不是在代码中直接创建。
- 结构型模式
结构型模式关注类和对象的组合,包括适配器模式、桥接模式、组合模式、装饰器模式、外观模式、享元模式和代理模式。
- 适配器模式:将一个类的接口转换成客户希望的另一个接口,使得原本接口不兼容的类可以一起工作。
- 桥接模式:将抽象部分和它的实现部分分离,使它们可以独立地变化。
- 组合模式:将对象组合成树形结构,以表示“部分-整体”的层次结构,并可以通过一个对象实例来操作整个树形结构。
- 装饰器模式:动态地给一个对象添加一些额外的职责,就增加功能来说,比生成子类更为灵活。
- 外观模式:为子系统中的一组接口提供一个统一的入口,使得在复杂的系统中能够更容易地进行操作。
- 享元模式:运用共享技术有效地支持大量细粒度的对象。
- 代理模式:为一个对象提供一个代用品或占位符,以便控制对它的访问。
- 行为型模式
行为型模式关注对象如何相互交互、解耦对象之间的职责分配,包括责任链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式和访问者模式。
- 责任链模式:避免请求发送者和接收者之间的耦合关系,使处理请求的对象连成一条链,并沿着这条链传递该请求,直到有对象处理为止。
- 命令模式:将请求封装成对象,从而使你可以用不同的请求对客户进行参数化,对请求排队和记录日志,以及支持可撤销的操作。
- 解释器模式:给定一个语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。
- 迭代器模式:提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示方式。
- 中介者模式:用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互作用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
- 备忘录模式:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,之后就可以将该对象恢复到原先保存的状态。
- 观察者模式:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。
- 状态模式:允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。
- 策略模式:定义一系列算法,把它们一个个封装起来,并且使它们可相互替换,本模式让算法的变化独立于使用它的客户。
- 模板方法模式:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。
- 访问者模式:表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变各元素类的前提下定义作用于这些元素的新操作。
3.单例
双重检查
-
class Singleton {
-
private static volatile Singleton instance;
-
private Singleton() {
-
}
-
private static Singleton getInstance() {
-
if (instance == null) {
-
synchronized (Singleton.class) {
-
if (instance == null) {
-
instance = new Singleton();
-
}
-
}
-
}
-
return instance;
-
}
-
}
3.计算机网络
1.OSI 7层模型和TCP/IP五层模型
应用层
最靠近用户的一层,为用户直接提供各种网络服务,比如我们看到的图片,听的音乐,看的视频常见的有HTTP,HTTPS协议 http是基于tcp和udp的
表示层
把人类看到的图片听到的声音用计算机编码表示,可以实现数据加密
高版本qq给低版本qq发表情,低版本qq解密不了
会话层
加两个app之间建立连接,比如美团只能用微信支付,淘宝只能用支付宝支付
qq发信息对方应该用qq接收,而不是微信
传输层
建立端到端的连接,比如我的电脑到你的电脑
建立TCP和UDP连接
TCP:适合传输那种对完整度要求高的文件,丢包就打不开的那种,有可靠性
UDP:可以接受少量丢包,对延迟要求很高,快,无可靠性
网络层
选择传递数据的最佳路径,选择合适的路由进行传输 ,ip协议
数据链路层
定义数据该以什么样的形式进行传输,比如网线是电信号,光纤是光信号
物理层
定义了传输介质,比如网线,光纤,什么样的东西才叫网线,什么样的东西才叫光纤
2.TCP和UDP的区别
UDP(面向报文)
1. 面向无连接
首先 UDP 是不需要和 TCP一样在发送数据前进行三次握手建立连接的,想发数据就可以开始发送了。并且也只是数据报文的搬运工,不会对数据报文进行任何拆分和拼接操作。
具体来说就是:
-
在发送端,应用层将数据传递给传输层的 UDP 协议,UDP 只会给数据增加一个 UDP 头标识下是 UDP 协议,然后就传递给网络层了
-
在接收端,网络层将数据传递给传输层,UDP 只去除 IP 报文头就传递给应用层,不会任何拼接操作
2. 有单播,多播,广播的功能
UDP 不止支持一对一的传输方式,同样支持一对多,多对多,多对一的方式,也就是说 UDP 提供了单播,多播,广播的功能。
3. UDP是面向报文的
没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低
发送方的UDP对应用程序交下来的报文,在添加首部后就向下交付IP层。
UDP对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界。因此,应用程序必须选择合适大小的报文
4. 不可靠性
首先不可靠性体现在无连接上,通信都不需要建立连接,想发就发,这样的情况肯定不可靠。
并且收到什么数据就传递什么数据,并且也不会备份数据,发送数据也不会关心对方是否已经正确接收到数据了。
再者网络环境时好时坏,但是 UDP 因为没有拥塞控制,一直会以恒定的速度发送数据。即使网络条件不好,也不会对发送速率进行调整。这样实现的弊端就是在网络条件不好的情况下可能会导致丢包,但是优点也很明显,在某些实时性要求高的场景(比如电话会议)就需要使用 UDP 而不是 TCP。
从上面的动态图可以得知,UDP只会把想发的数据报文一股脑的丢给对方,并不在意数据有无安全完整到达。
4.UDP支持一对一,一对多,多对一和多对多的交互通信
5. 头部开销小,传输数据报文时是很高效的。
UDP 头部包含了以下几个数据:
-
两个十六位的端口号,分别为源端口(可选字段)和目标端口
-
整个数据报文的长度
-
整个数据报文的检验和(IPv4 可选 字段),该字段用于发现头部信息和数据中的错误
因此 UDP 的头部开销小,只有八字节,相比 TCP 的至少二十字节要少得多,在传输数据报文时是很高效的
TCP(面向字节流)
引言:当你下载文件时,希望获得的是完整的文件,而不仅仅是文件的一部分,因为如果数据丢失或乱序,都不是你希望得到的结果,于是就用到了TCP。
TCP协议全称是传输控制协议是一种面向连接的、可靠的、基于字节流的传输层通信协议,由 IETF 的RFC 793定义。TCP 是面向连接的、可靠的流协议。流就是指不间断的数据结构,你可以把它想象成排水管中的水流
-
CLOSED:初始状态,表示TCP连接是”关闭着的”或”未打开的”
-
LISTEN:表示服务器端的某个SOCKET处于监听状态,可以接受客户端的连接
-
SYN_RCVD:表示服务器接收到了来自客户端请求连接的SYN报文。这个状态是在服务端的,但是它是一个中间状态,很短暂,平常我们用netstat或ss的时候,不太容易看到这种状态,但是遇到SYN flood之类的SYN攻击时,会出现大量的这种状态,即收不到三次握手最后一个客户端发来的ACK,所以一直是这个状态,不会转换到ESTABLISHED
-
SYN_SENT:这个状态与SYN_RCVD状态相呼应,,它是TCP连接客户端的状态,当客户端SOCKET执行connect()进行连接时,它首先发送SYN报文,然后随机进入到SYN_SENT状态,并等待服务端的SYN和ACK,该状态表示客户端的SYN已发送
-
ESTABLISHED:表示TCP连接已经成功建立,开始传输数据
1.TCP连接过程
篇幅限制下面就只能给大家展示小册部分内容了。整理了一份核心面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题
需要全套面试笔记的【点击此处即可】即可免费获取
第一次握手
客户端向服务端发送连接请求报文段。该报文段中包含自身的数据通讯初始序号。请求发送后,客户端便进入 SYN-SENT 状态。
第二次握手
服务端收到连接请求报文段后,如果同意连接,则会发送一个应答,该应答中也会包含自身的数据通讯初始序号,发送完成后便进入 SYN-RECEIVED 状态。
第三次握手
当客户端收到连接同意的应答后,还要向服务端发送一个确认报文。客户端发完这个报文段后便进入 ESTABLISHED 状态,服务端收到这个应答后也进入 ESTABLISHED 状态,此时连接建立成功。
这里可能大家会有个疑惑:为什么 TCP 建立连接需要三次握手,而不是两次?
这是因为这是为了防止出现失效的连接请求报文段被服务端接收的情况,从而产生错误。
客户端向服务端建立连接确认了,但是服务端向客户端没有确认
2. TCP断开链接
-
FIN_WAIT_1:这个状态在实际工作中很少能看到,当客户端想要主动关闭连接时,它会向服务端发送FIN报文,此时TCP状态就进入到FIN_WAIT_1的状态,而当服务端回复ACK,确认关闭后,则客户端进入到FIN_WAIT_2的状态,也就是只有在没有收到服务端ACK的情况下,FIN_WAIT_1状态才能看到,然后长时间收不到ACK,通常会在默认超时时间60s(由内核参数tcp_fin_timeout控制)后,直接进入CLOSED状态
-
FIN_WAIT_2:这个状态相比较常见,也是需要注意的一个状态,FIN_WAIT_1在接收到服务端ACK之后就进入到FIN_WAIT_2的状态,然后等待服务端发送FIN,所以在收到对端FIN之前,TCP都会处于FIN_WAIT_2的状态,也就是,在主动断开的一端发现大量的FIN_WAIT_2状态时,需要注意,可能时网络不稳定或程序中忘记调用连接关闭,FIN_WAIT_2也有超时时间,也是由内核参数tcp_fin_timeout控制,当FIN_WAIT_2状态超时后,连接直接销毁
-
CLOSE_WAIT:表示正在等待关闭,该状态只在被动端出现,即当主动断开的一端调用close()后发送FIN报文给被动端,被动段必然会回应一个ACK(这是由TCP协议层决定的),这个时候,TCP连接状态就进入到CLOSE_WAIT
-
LAST_ACK:当被动关闭的一方在发送FIN报文后,等待对方的ACK报文的时候,就处于LAST_ACK的状态,当收到对方的ACK之后,就进入到CLOSED状态了
-
TIME_WAIT:该状态是最常见的状态,主动方在收到对方FIN后,就由FIN_WAIT_2状态进入到TIME_WAIT状态
-
CLOSING:这个状态是一个比较特殊的状态,也比较少见,正常情况下不会出现,但是当双方同时都作为主动的一方,调用 close() 关闭连接的时候,两边都进入FIN_WAIT_1 的状态,此时期望收到的是ACK包,进入 FIN_WAIT_2 的状态,但是却先收到了对方的FIN包,这个时候,就会进入到 CLOSING 的状态,然后给对方一个ACK,接收到 ACK 后直接进入到 CLOSED 状态。
TCP 是全双工的,在断开连接时两端都需要发送 FIN 和 ACK。
第一次挥手
若客户端 A 认为数据发送完成,则它需要向服务端 B 发送连接释放请求。(A告诉B我要释放连接了)
第二次挥手
B 收到连接释放请求后,会告诉应用层要释放 TCP 链接。然后会发送 ACK 包,并进入 CLOSE_WAIT 状态,此时表明 A 到 B 的连接已经释放,不再接收 A 发的数据了。但是因为 TCP 连接是双向的,所以 B 仍旧可以发送数据给 A。(B回答好的,然后A->B连接就释放)
第三次挥手
B 如果此时还有没发完的数据会继续发送,完毕后会向 A 发送连接释放请求,然后 B 便进入 LAST-ACK 状态。
第四次挥手
A 收到释放请求后,向 B 发送确认应答,此时 A 进入 TIME-WAIT 状态。该状态会持续 2MSL(最大段生存期,指报文段在网络中生存的时间,超时会被抛弃) 时间,若该时间段内没有 B 的重发请求的话,就进入 CLOSED 状态。当 B 收到确认应答后,也便进入 CLOSED 状态。
拓展:2和3可以合在一起吗
不可以,也许服务端还要发数据
3.TCP怎么保证可靠性传输TCP(传输控制协议)
-
应答机制:发送方发送数据后,接收方会发送一个确认消息(ACK)来告诉发送方数据已经接收到。如果发送方没有收到确认消息,它会重发数据,直到接收方确认接收到数据。
-
序列号和确认号:每个TCP报文段都有一个序列号和确认号。序列号表示报文段中第一个字节的编号,而确认号表示期望收到的下一个字节的编号。这些序列号和确认号可以防止数据包丢失或乱序。
-
滑动窗口:TCP使用滑动窗口机制来控制发送方和接收方之间的数据流量。发送方会根据接收方的窗口大小来发送数据,而接收方会根据自己的处理能力来调整窗口大小。这样可以避免发送方发送过多数据导致接收方无法处理。
-
超时重传:如果发送方没有收到确认消息,它会等待一段时间(超时时间),然后重新发送数据。如果多次重发后仍未收到确认消息,则认为连接已经中断。
-
流量控制:TCP使用流量控制机制来防止发送方发送过多的数据导致接收方无法处理。接收方会告诉发送方自己的窗口大小,发送方会根据窗口大小来发送数据。
通过这些机制,TCP可以保证数据的可靠性传输,即使在网络环境不稳定的情况下也能保证数据的完整性和可靠性。
tcp滑动窗口,拥塞控制
TCP(Transmission Control Protocol)是一种面向连接的传输协议,它通过滑动窗口和拥塞控制等机制实现高效可靠的数据传输。
滑动窗口是 TCP 实现流控制的重要机制,它允许发送方和接收方在数据传输过程中控制发送和接收的数据量。发送方和接收方各自维护一个滑动窗口,用于控制数据的流动。滑动窗口的大小可以动态调整,它是由发送方和接收方之间的通信延迟和网络带宽等因素决定的。
TCP 还实现了拥塞控制机制,通过控制发送方的发送速率,以避免网络出现拥塞情况。TCP 通过拥塞窗口来限制发送方的数据发送速率,即通过控制滑动窗口的大小来实现拥塞控制。在拥塞控制过程中,TCP 通过慢启动、拥塞避免和快重传等算法,根据网络状况动态调整拥塞窗口的大小,以提高网络传输效率和可靠性。
TCP 滑动窗口和拥塞控制机制的综合作用,使得 TCP 协议在数据传输方面具有良好的性能和可靠性,尤其适合用于可靠传输的应用场景。
4.HTTP1.0、HTTP1.1、HTTP2.0、HTTP3.0
HTTP1.0默认使用 Connection:cloose
,浏览器每次请求都需要与服务器建立一个 TCP 连接,服务器处理完成后立即断开 TCP 连接(无连接),服务器不跟踪每个客户端也不记录过去的请求(无状态)。
HTTP1.1默认使用 Connection:keep-alive
(长连接),避免了连接建立和释放的开销;通过 Content-Length 字段来判断当前请求的数据是否已经全部接受。不允许同时存在两个并行的响应。
HTTP2.0新特性
(1)二进制传输
http2.0将请求和响应数据分割为更小的帧,并且它们采用二进制编码(http1.0基于文本格式)。多个帧之间可以乱序发送,根据帧首部的流表示可以重新组装。
(2)Header压缩
Http2.0开发了专门的“HPACK”算法,大大压缩了Header信息。
(3)多路复用
http2.0中引入了多路复用技术,很好的解决了浏览器限制同一个域名下的请求数量的问题。
多路复用技术可以只通过一个TCP链接就可以传输所有的请求数据。
(4)服务端推送
HTTP2.0在一定程度上改不了传统的“请求-应答”工作模式,服务器不再完全被动地响应请求,也可以新建“流”主动向客户端发送消息。(例如,浏览器在刚请求html的时候就提前把可能会用到的JS,CSS文件发送给客户端,减少等待延迟,这被称为“服务端推送Server Push”)
Http3.0 抛弃tcp
Google在推行SPDY的时候意识到了上述http2.0一系列问题,于是又产生了基于UDP协议的“QUIC”协议,让HTTP跑在QUIC上而不是TCP上。从而产生了HTTP3.0版本,它解决了“队头阻塞”的问题。
- 特点:
(1)实现了类似TCP的流量控制,传输可靠性的功能。
(2)实现了快速握手功能(QUIC基于UDP,UDP是面向无连接的,不需要握手和挥手,比TCP快)
(3)集成了TLS加密功能
(4)多路复用,彻底解决TCP中队头阻塞的问题(单个“流”是有序的,可能会因为丢包而阻塞,但是其他流不会受到影响)
5.https
https是在应用层和传输层之间加了一个安全层,应用层与安全层进行加密,安全层再与传输层进行交互
1.客户端把它支持的加密算法传给服务端
2.服务端给客户端一个公钥和他的数字证书
3.客户端验证证书,发现这个公钥是我自己的,之后生成随机的对称秘钥,用公钥加密
4.用私钥解密获得秘钥
5.传输数据
签名:由私钥生成
传输的时候传数据和它独有的签名,别人收到用签名和数据对比,如果一样则安全,不一样就丢弃
证书:保护公钥不被篡改
对称性加密算法和非对称性加密算法
对称性加密算法:
对称性加密算法使用同样的密钥,用于加密和解密数据。由于密钥需要在双方之间共享,因此需要确保密钥在传输过程中不被泄露。对称性加密算法一般采用比较快速的加密算法,因此在加密大量数据时通常比非对称加密算法更具有优势。下面是几个常见的对称性加密算法:
- DES算法:Data Encryption Standard,是一种基于密码学的对称性加密算法,用于加密电子数据。
- AES算法:Advanced Encryption Standard,是一种基于密码学的高级对称性加密算法,用于加密电子数据。
- Blowfish算法:是一种基于密码学的对称性加密算法,可以用来加密小到大的数据块。它的优点是速度快、安全、经过广泛的测试。
非对称加密算法:
非对称加密算法使用不同的密钥,其中一个用于加密数据,另一个用于解密数据。加密密钥被公开,而解密密钥则需要存储在安全的地方。非对称加密算法通常用于加密短消息、数字签名等需要高度安全性的数据。下面是几个常见的非对称加密算法:
- RSA算法:是一种非对称加密算法,广泛用于数字签名和安全信任建立等领域。它能够支持多种密钥长度,通常用于加密短消息。
- DSA算法:数字签名算法,用于在数字文档上确定其作者身份的一种标准算法。
- ElGamal算法:是由ElGamal发明的一种非对称加密算法,在加密过程中能够提供完全性证明。
散列算法:
-
MD5 (Message Digest Algorithm 5):MD5 是一个广泛使用的散列算法之一。它接收字符串作为输入,并生成具有固定大小的唯一的散列值。通常,它会生成一个 128 位长的十六进制数字,用于验证数据的完整性。
-
SHA (Secure Hash Algorithm):SHA 是另一个常用的散列算法。它有几种不同的变体,但最广泛使用的变体是 SHA-256 和 SHA-512。SHA-256 生成一个 256 位长的散列值,而 SHA-512 生成一个 512 位长的值。
-
MurmurHash:MurmurHash 是一个比 MD5 和 SHA 更快的散列算法。它在散列大量数据时非常高效,并且生成的散列值具有良好的随机性和均匀分布性。它被广泛用于哈希表等需要高效哈希函数的场景。
篇幅限制下面就只能给大家展示小册部分内容了。整理了一份核心面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题
需要全套面试笔记的【点击此处即可】即可免费获取
https为什么安全
HTTPS的安全性建立在Transport Layer Security(TLS)协议(前身是Secure Sockets Layer(SSL)协议)上。
HTTPS之所以安全,是因为使用了一些加密技术和安全机制,包括:
-
数据传输加密:HTTPS使用公钥加密和私钥解密的方式对数据进行传输加密,防止数据传输过程中被窃取或篡改。
-
客户端验证:HTTPS实现了双向认证,即客户端和服务器双方都需要进行验证,确保通信双方的身份和合法性。
-
数据完整性保护:HTTPS使用数据摘要技术和数字签名机制来保护数据的完整性。在数据传输结束后,接收方可以通过验证数据摘要和数字签名来确定数据是否被篡改。
-
防止中间人攻击:HTTPS使用非对称加密算法来保证数据传输的安全性,避免中间人攻击。这是因为HTTPS使用公钥加密和私钥解密的方式,数据只能由私钥持有者读取,即使在传输过程中被截获,攻击者也无法解密。
综上所述,HTTPS之所以安全,是因为它使用了多种加密技术和安全机制,确保了数据在传输过程中的保密性、完整性和合法性。这些技术和机制为网站和用户之间的数据传输提供了强有力的安全保障。
4.操作系统
1.linux的进程状态 ????
*R (TASK_RUNNING),可执行状态。* running
*S (TASK_INTERRUPTIBLE),可中断的睡眠状态。*sleep
*D (TASK_UNINTERRUPTIBLE),不可中断的睡眠状态。*
*T (TASK_STOPPED or TASK_TRACED),暂停状态或跟踪状态*stop
*Z (TASK_DEAD - EXIT_ZOMBIE),退出状态,进程成为僵尸进程。*zombie
*:X (TASK_DEA
D - EXIT_DEAD),退出状态,进程即将被销毁。*exit
2.分段,分页机制
分段分页是操作系统中的内存管理机制,用于将物理内存和逻辑内存进行映射,以实现多道程序的并发执行和保护内存空间的安全性
考虑最原始,最直接的情况,程序中访问的地址都直接对应于物理地址。
这种方式有以下几个问题:两个使用的地址有交集的程序没法同时进行,就回导致各个程序之间无法隔离。
所以引入了分段机制。那么什么是分段机制呢? 将内存分成一段一段的(段大小不固定),为程序被分配某个段之后,程序便只能访问固定的段,无法访问其他地址
那么分页就是
将地址分为大小固定的页(一般为4096字节),按页为单位进行映射。连续的线性地址可以映射到不连续的的物理内存上
段式管理:
优点:消除了内部碎片,提高了对物理内存的利用率;将应用按逻辑分段,人们可以编写不同类型的代码,可以方便的进行共享或保护。
缺点:会产生大量的外部碎片,使得操作系统难以分配空闲空间。
页式管理:
优点:消除了外部碎片,提高了对物理内存的利用率,利于操作系统管理空闲空间。
缺点:仍然会产生内部碎片,尽管每个页碎片不超过页的大小;页表过大,占用大量空间,可以采用多级页表思想解决。
段页式管理:
优点:同时具备段式和页式的所有优点。
缺点:需要更多的硬件支持;当TLB未命中,需要更多的时间访问内存。
3.操作系统底层文件的管理通常涉及到以下几个方面:
文件系统通常会将文件的数据分成多个数据块(Data Block)存储,每个数据块的大小通常为 4KB 或 8KB。当文件的大小超过一个数据块时,文件系统会将文件的数据分成多个数据块存储,并记录每个数据块的地址和大小等信息。
当应用程序需要访问文件时,操作系统会根据文件系统的目录结构找到文件的位置,并读取文件的数据块。如果文件的数据块在内存中,则直接读取内存中的数据;否则,操作系统会从磁盘等外存中将数据块读取到内存中,然后再读取数据。
5.mysql
1.Mysql的存储引擎
首先数据库的存储引擎是基于表的而不是基于数据库的,存储引擎就是数据的存储方式
然后mysql支持很多存储引擎,但我们常用的有3种
1.Innodb:支持事务,支持行锁,支持外键,底层是两个文件,一个里面存表结构,一个里面存数据和索引
2.myisam:不支持事务,但查询快,,底层是三个文件,平均分布io,获得更快的速度
3.memery:速度最快,只存储表结构,剩下都存在内存
MyIsam为什么比innodb快
-
由于innodb支持事务,所以会有mvvc的一个比较。这个过程会浪费性能。
-
查询的时候,innodb叶子节点存储的是数据块,查询时找到数据块才能找到对应行.MyIsam叶子节点存储的是磁盘地址,所以,查询的时候查到的最后结果不是聚簇索引树的key,而是会直接去查询磁盘。
-
锁的一个损耗,innodb锁支持行锁,在检查锁的时候不仅检查表锁,还要看行锁。
Innodb底层的四大组件
1.Buffer Pool:
用来缓存数据的内存池,缓存的是最热门的数据页。在 InnoDB 存储引擎中,数据存储在由具体页组成的数据文件中,而 Buffer Pool 则缓存着热门的数据页,以避免频繁的磁盘 I/O 操作。Buffer Pool 的大小可以通过参数 innodb_buffer_pool_size 进行设置,一般建议为总内存的 60~80%。
什么是double_write双写?
mysql在写入数据时会先写在缓冲区,再写到数据页也就是磁盘。防止数据页损坏。
当数据还在缓冲池中的时候,当机器宕机了,发生了写失效,有Redo Log来进行恢复。但是如果是在从缓冲池中将数据刷回磁盘的时候宕机了呢?
这种情况叫做部分写失效,此时重做日志就无法解决问题。
当 InnoDB 存储引擎要将脏数据页写入磁盘时,它首先会将数据页的副本写入缓冲区,再将数据页的副本写入磁盘的数据文件中。
2.Change Buffer:
Change Buffer 相当于一个写入缓存,由于 InnoDB 存储引擎在处理写入操作时需要先定位到对应的磁盘页然后再更新数据,而 I/O 操作往往是数据库性能的瓶颈,因此 Change Buffer 用来缓存更新数据的那一部分,以减少 I/O 操作。Change Buffer 缓存的数据是未被写入磁盘的,并且会在 Buffer Pool 内存不足时转移到磁盘。
由 Insert Buffer 和 Update Buffer 两部分组成。Insert Buffer 用于缓存插入操作所产生的记录,而 Update Buffer 用于缓存更新和删除操作所产生的修改。
当一个事务需要插入、删除或更新记录时,InnoDB 不会直接写入磁盘,而是首先将修改缓存到 Change Buffer 中,InnoDB 会将修改的数据页标记为“脏页”,稍后会将 通过double_write合并到对应的磁盘页中。因为缓存到 Change Buffer 中的修改可以批量写入磁盘,因此在缓存中的修改可以减少磁盘 I/O 操作,提高了事务的处理速度。
Change Buffer 在某些条件下并不适用,例如内存不足、更新批量过大或者对于主键更新频繁等情况下。在这些情况下,Change Buffer 会被禁用,修改直接落盘到磁盘进行更新。
3.自适应哈希索引:
Adaptive Hash Index(简称 AHI)则是 InnoDB 存储引擎用来加速查询的一种索引。自适应哈希索引的主要思想是为频繁访问的数据建立 hash 索引,在查询时能很快地定位到对应的数据块,避免了在 B+ 树中进行多次磁盘 I/O 操作,进而提高了查询效率。自适应哈希索引采用的是一种自适应性策略,能够动态地调整索引的大小、数量和位置,从而适应数据访问的变化。
4.Log Buffer:
Log Buffer 是 InnoDB 存储引擎中用来加速日志写入操作的缓存区域,它缓存着待写入到磁盘上的 redo log,可以减少频繁的磁盘操作,从而提高性能。Log Buffer 的大小可以通过参数 innodb_log_buffer_size 进行设置。
2.事务的四大特性ACID
事务通常以BEGIN TRANSACTION开始,以COMMIT或ROLLBACK结束
首先,什么是事务,我理解为一些操作的集合
1.原子性: undolog
事务包含的操作,是一个原子性操作,要么都成功,要么都失败
2.一致性: undolog
事务执行前后必须处于一致性状态
拿转账来说,假设用户A和用户B两者的钱加起来一共是5000,那么不管A和B之间如何转账,转几次账,事务结束后两个用户的钱相加起来应该还得是5000,这就是事务的一致性。
3.隔离性: MVCC
事务之间相互独立,一个事务执行不能被其他事务干扰
即要达到这么一种效果:对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行。
4.持久性: redolog
篇幅限制下面就只能给大家展示小册部分内容了。整理了一份核心面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题
需要全套面试笔记的【点击此处即可】即可免费获取
持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的
3.事务在并发条件下产生的问题
1.脏读:
A事务读取了B事务未提交的数据
2.不可重复读:
A事务对自己未操作的数据进行多次读取,结果发现数据不一致的情况(破坏一致性)
3.幻读:
有的人说幻读是,A事务查询得到了n条数据,事务b此时对表进行增加或者删除,之后事务A有进行了查询,发现条数不一样
但我不这么,我是这样理解的
A事务查某条记录是否存在,结果不存在,然后他插入数据,插不进去
12.事务的隔离级别
主要就是读取的是哪个版本的数据
1.读未提交(read uncommitted)
脏读,不可重复读,幻读都有可能发生
2.读已提交(read committed) 每次快照读
避免脏读rc
每次执行快照读的时候生成readview
3.可重复读(repeatable read) 一次快照读
避免脏读,不可重复读rr,在快照读时避免幻读,当前读时会产生幻读.
第一次执行快照读的时候生成readview
当执行update、delete、insert是当前读
4.串行化(serializable)
当前读,因为加入共享读锁
避免脏读,不可重复读,幻读
当前读:
select for update insert,update,delete
快照读:某一时间点的数据,就像对数据拍了一张照片
4.innodb中主键索引和非主键索引都是聚簇索引吗
不是
聚簇索引具有唯一性
由于聚簇索引是将数据跟索引结构放到一块,因此一个表仅有一个聚簇索引
总结:当有主键时聚簇索引,因为一张表中没有主键索引,那么聚簇索引会使用第一个唯一索引(此列必须为not null),如果以上情况都不满足,那么InnoDB会生成一个隐藏的聚簇索引。
5.事务的原理,回滚的实现
有一个日志,undolog
当有事务对数据进行操作时,会在undolog上产生一条记录
他记录了当前事务的id和回滚指针
完了他就实现了回滚
6.mysql主从复制
1.为什么需要主从复制
1.如果有一句sql语句需要锁表导致暂时不能够使用读服务,那么很影响性能,使用主从复制,让主库负责写,从库负责读
2.做数据的热备,相当于给主库做一个备份
3.业务量大,I/O访问频率过高,降低磁盘的访问频率,提高单个机器的I/O量
2.主从复制原理
1.主服务器将数据的改变记录记录在binlog日志,当主服务器上的数据发生改变,将改变写入binlog日志(binlog的写入必须要等待事务完成之后,才会传入备库)
2.从服务器在一定时间间隔内对主服务器的binlog日志探测是否改变,如果发生改变,则开始一个I/O线程请求主服务器的事件
3.主库接收到请求就为开一个log dump线程,用来给从库传binlog,写到本地的relay-log(中继文件)文件中
传完,从库开启一个sql的线程,把读到的都执行一遍,与主服务器保持一致
4.复制延迟如何解决
不可能解决,可以在两个mysql服务器之间添加缓存.
5.如何实现读写分离
主从复制依赖于读写分离
1.通过一个mysql代理(lua脚本写的,可以识别出读和写的sql语句,然后进行转发),但不常用,因为性能
不高
6.Binlog的三种形式的优缺点
- Statement-Based Logging(基于语句的日志)
该方式 Binlog 记录的是 MySQL 执行的 SQL 语句。这种日志记录方式比较简单,记录的数据量相对较小,存储空间开销较小,对 CPU 的消耗也相对较小。这种方式可减轻系统的磁盘 I/O 压力,因为它只需要写入 Binlog 中的 SQL 语句即可。
但是由于基于语句的方式是记录 SQL 语句,因此只要语句相同,执行结果也相同。但是,同一 SQL 语句的多次执行结果在不同时间或环境下可能有所不同,所以在恢复数据时稍有风险。
比如地理位置不同就会导致时间不同
- Row-Based Logging(基于行的日志)
该方式 Binlog 记录针对每行数据所执行的修改操作的结果。由于该方式是对每行数据进行记录的,所以可以准确地恢复出原操作,使得数据更具备一致性。而且它能够记录插入和删除操作,甚至是对于原始状态没有改变的 UPDATE 操作都记录了修改前和修改后的状态。
但是这种记录方式产生的日志数据量较大,占用存储空间也高,对 CPU 的消耗也相对较高。
一条修改和删除的sql语句可能伴随着多个表的行的变动,日志需要记录每个表每个行的变动导致文件变大
- Mixed Logging(混合日志)
该方式结合了基于语句和基于行的记录方式,使得使用组合方式可以充分发挥它们的长处。MySQL 可以自己判断一个请求的 SQL 语句是否适合由 Statement-Based Logging 方式进行记录,如果 SQL 操作适合于采用 Row-Based Logging 方式,MySQL 将自动采用 Row-Based Logging。
当 MySQL 无法确定使用哪种日志格式时(例如,涉及到表中 BLOB 或 TEXT 类型),它将使用 Mixed Logging。这种方式既保证了数据的完整性,也减小了存储空间和 CPU 占用的开销。
综上所述,每种日志记录方式都有其自身的优缺点。Statement-Based Logging 简单、存储空间和 CPU 占用小,但是恢复时有一定的风险;Row-Based Logging 记录准确,恢复数据时风险较小,但是存储空间比较大,对 CPU 占用也较高;而 Mixed Logging 将两种方式组合使用,可以在存储空间和 CPU 占用方面取得一个折中的结果,但是可能会牺牲一定的查询性能。因此,我们需要根据不同的应用场景来选择适合的 Binlog 日志记录方式。
7.谈一下你对MVCC的理解
MVCC是多版本并发控制(Multi-Version Concurrency Control)的缩写,是一种并发控制机制。MVCC机制通过创建多个版本的数据,来实现多个事务并发地读取或修改同一数据,从而提高并发性和性能。
在MVCC机制中,每个事务操作的数据都被保存在多个版本上,并根据时间戳进行管理。当一个事务读取数据时,它会读取其中的某个版本。当进行更新操作时,会将新的版本存储到数据中,并将旧的版本作为历史版本保存。在整个事务过程中,每个事务都只能看到它启动时的数据版本,从而保证了事务的隔离性和一致性。并且,MVCC机制还可以避免死锁的情况,提高了并发性能。
如何解决幻读
将数据库事务的隔离级别设置成串行化;或者使用乐观锁,使用版本号或时间戳字段,每次更新数据时检查版本号或时间戳是否匹配,以确保数据的一致性;在读取数据时加锁,以防止其他事务修改数据。可以使用SELECT ... FOR UPDATE
语句来实现。
8.索引分类
按数据结构分类可分为:B+tree索引、Hash索引、Full-text索引。 按物理存储分类可分为:聚簇索引、二级索引(辅助索引)。 按字段特性分类可分为:主键索引、普通索引、前缀索引。 按字段个数分类可分为:单列索引、联合索引(复合索引、组合索引)。
聚簇索引:聚簇索引可以直接找到数据innodb
非聚簇索引:至少经历两次查找,先找到聚簇索引,再找到数据(MyIsam)
9.执行计划
MySQL的执行计划(Execution Plan)是指MySQL优化器根据SQL语句所生成的查询计划,描述了MySQL如何执行该查询语句。执行计划显示了MySQL选择的查询方式、所使用的索引、表连接顺序、数据读取方式等详细信息,能够帮助我们理解MySQL的查询优化过程和性能瓶颈,从而进行优化。
在MySQL中,我们可以通过EXPLAIN语句来查看执行计划。EXPLAIN语句可以在SELECT、DELETE、INSERT、REPLACE和UPDATE语句前加上,例如:
``` EXPLAIN SELECT * FROM table_name WHERE column1 = 'value'; ```
执行该语句后,MySQL会返回一个表格,其中包含了查询的详细信息,例如:
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | 1 | SIMPLE | table_name | NULL | ref | column1_index | column1_index | 767 | const | 1 | 100.00 | NULL |
在表格中,每一行对应一个访问表的操作,其中包含了该操作所用的索引、访问方式、读取行数、过滤条件等信息。通过分析执行计划,我们可以判断查询中是否使用了索引,索引是否命中,是否存在全表扫描等问题,从而优化查询性能。
10.索引结构
注意:innodb只支持B tree ,Memery支持hash
-
BTREE 索引 :
-
最常见的索引类型,大部分索引都支持 B 树索引。
-
-
HASH 索引:
-
只有Memory引擎支持 , 使用场景简单 。
-
-
R-tree 索引(空间索引):
-
空间索引是MyISAM引擎的一个特殊索引类型,主要用于地理空间数据类型,通常使用较少,不做特别介绍。
-
-
Full-text (全文索引) :
-
全文索引也是MyISAM的一个特殊索引类型,主要用于全文索引,InnoDB从Mysql5.6版本开始支持全文索引。
篇幅限制下面就只能给大家展示小册部分内容了。整理了一份核心面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题
需要全套面试笔记的【点击此处即可】即可免费获取
-