Skip to content

Commit 3b1767d

Browse files
committed
[docs update]数据库和网络部分问题答案优化完善
1 parent ff77b0c commit 3b1767d

File tree

5 files changed

+537
-442
lines changed

5 files changed

+537
-442
lines changed

docs/cs-basics/network/other-network-questions2.md

+49-19
Original file line numberDiff line numberDiff line change
@@ -11,31 +11,61 @@ tag:
1111

1212
### TCP 与 UDP 的区别(重要)
1313

14-
1. **是否面向连接**:UDP 在传送数据之前不需要先建立连接。而 TCP 提供面向连接的服务,在传送数据之前必须先建立连接,数据传送结束后要释放连接。
15-
2. **是否是可靠传输**:远地主机在收到 UDP 报文后,不需要给出任何确认,并且不保证数据不丢失,不保证是否顺序到达。TCP 提供可靠的传输服务,TCP 在传递数据之前,会有三次握手来建立连接,而且在数据传递时,有确认、窗口、重传、拥塞控制机制。通过 TCP 连接传输的数据,无差错、不丢失、不重复、并且按序到达。
16-
3. **是否有状态**:这个和上面的“是否可靠传输”相对应。TCP 传输是有状态的,这个有状态说的是 TCP 会去记录自己发送消息的状态比如消息是否发送了、是否被接收了等等。为此 ,TCP 需要维持复杂的连接状态表。而 UDP 是无状态服务,简单来说就是不管发出去之后的事情了(**这很渣男!**)。
17-
4. **传输效率**:由于使用 TCP 进行传输的时候多了连接、确认、重传等机制,所以 TCP 的传输效率要比 UDP 低很多。
18-
5. **传输形式**:TCP 是面向字节流的,UDP 是面向报文的。
19-
6. **首部开销**:TCP 首部开销(20 ~ 60 字节)比 UDP 首部开销(8 字节)要大。
20-
7. **是否提供广播或多播服务**:TCP 只支持点对点通信,UDP 支持一对一、一对多、多对一、多对多;
14+
1. **是否面向连接**
15+
- TCP 是面向连接的。在传输数据之前,必须先通过“三次握手”建立连接;数据传输完成后,还需要通过“四次挥手”来释放连接。这保证了双方都准备好通信。
16+
- UDP 是无连接的。发送数据前不需要建立任何连接,直接把数据包(数据报)扔出去。
17+
2. **是否是可靠传输**
18+
- TCP 提供可靠的数据传输服务。它通过序列号、确认应答 (ACK)、超时重传、流量控制、拥塞控制等一系列机制,来确保数据能够无差错、不丢失、不重复且按顺序地到达目的地。
19+
- UDP 提供不可靠的传输。它尽最大努力交付 (best-effort delivery),但不保证数据一定能到达,也不保证到达的顺序,更不会自动重传。收到报文后,接收方也不会主动发确认。
20+
3. **是否有状态**
21+
- TCP 是有状态的。因为要保证可靠性,TCP 需要在连接的两端维护连接状态信息,比如序列号、窗口大小、哪些数据发出去了、哪些收到了确认等。
22+
- UDP 是无状态的。它不维护连接状态,发送方发出数据后就不再关心它是否到达以及如何到达,因此开销更小(**这很“渣男”!**)。
23+
4. **传输效率**
24+
- TCP 因为需要建立连接、发送确认、处理重传等,其开销较大,传输效率相对较低。
25+
- UDP 结构简单,没有复杂的控制机制,开销小,传输效率更高,速度更快。
26+
5. **传输形式**
27+
- TCP 是面向字节流 (Byte Stream) 的。它将应用程序交付的数据视为一连串无结构的字节流,可能会对数据进行拆分或合并。
28+
- UDP 是面向报文 (Message Oriented) 的。应用程序交给 UDP 多大的数据块,UDP 就照样发送,既不拆分也不合并,保留了应用程序消息的边界。
29+
6. **首部开销**
30+
- TCP 的头部至少需要 20 字节,如果包含选项字段,最多可达 60 字节。
31+
- UDP 的头部非常简单,固定只有 8 字节。
32+
7. **是否提供广播或多播服务**
33+
- TCP 只支持点对点 (Point-to-Point) 的单播通信。
34+
- UDP 支持一对一 (单播)、一对多 (多播/Multicast) 和一对所有 (广播/Broadcast) 的通信方式。
2135
8. ……
2236

23-
我把上面总结的内容通过表格形式展示出来了!确定不点个赞嘛?
37+
为了更直观地对比,可以看下面这个表格:
2438

25-
| | TCP | UDP |
26-
| ---------------------- | -------------- | ---------- |
27-
| 是否面向连接 |||
28-
| 是否可靠 |||
29-
| 是否有状态 |||
30-
| 传输效率 | 较慢 | 较快 |
31-
| 传输形式 | 字节流 | 数据报文段 |
32-
| 首部开销 | 20 ~ 60 bytes | 8 bytes |
33-
| 是否提供广播或多播服务 |||
39+
| 特性 | TCP | UDP |
40+
| ------------ | -------------------------- | ----------------------------------- |
41+
| **连接性** | 面向连接 | 无连接 |
42+
| **可靠性** | 可靠 | 不可靠 (尽力而为) |
43+
| **状态维护** | 有状态 | 无状态 |
44+
| **传输效率** | 较低 | 较高 |
45+
| **传输形式** | 面向字节流 | 面向数据报 (报文) |
46+
| **头部开销** | 20 - 60 字节 | 8 字节 |
47+
| **通信模式** | 点对点 (单播) | 单播、多播、广播 |
48+
| **常见应用** | HTTP/HTTPS, FTP, SMTP, SSH | DNS, DHCP, SNMP, TFTP, VoIP, 视频流 |
3449

3550
### 什么时候选择 TCP,什么时候选 UDP?
3651

37-
- **UDP 一般用于即时通信**,比如:语音、 视频、直播等等。这些场景对传输数据的准确性要求不是特别高,比如你看视频即使少个一两帧,实际给人的感觉区别也不大。
38-
- **TCP 用于对传输准确性要求特别高的场景**,比如文件传输、发送和接收邮件、远程登录等等。
52+
选择 TCP 还是 UDP,主要取决于你的应用**对数据传输的可靠性要求有多高,以及对实时性和效率的要求有多高**
53+
54+
**数据准确性和完整性至关重要,一点都不能出错**时,通常选择 TCP。因为 TCP 提供了一整套机制(三次握手、确认应答、重传、流量控制等)来保证数据能够可靠、有序地送达。典型应用场景如下:
55+
56+
- **Web 浏览 (HTTP/HTTPS):** 网页内容、图片、脚本必须完整加载才能正确显示。
57+
- **文件传输 (FTP, SCP):** 文件内容不允许有任何字节丢失或错序。
58+
- **邮件收发 (SMTP, POP3, IMAP):** 邮件内容需要完整无误地送达。
59+
- **远程登录 (SSH, Telnet):** 命令和响应需要准确传输。
60+
- ......
61+
62+
**实时性、速度和效率优先,并且应用能容忍少量数据丢失或乱序**时,通常选择 UDP。UDP 开销小、传输快,没有建立连接和保证可靠性的复杂过程。典型应用场景如下:
63+
64+
- **实时音视频通信 (VoIP, 视频会议, 直播):** 偶尔丢失一两个数据包(可能导致画面或声音短暂卡顿)通常比因为等待重传(TCP 机制)导致长时间延迟更可接受。应用层可能会有自己的补偿机制。
65+
- **在线游戏:** 需要快速传输玩家位置、状态等信息,对实时性要求极高,旧的数据很快就没用了,丢失少量数据影响通常不大。
66+
- **DHCP (动态主机配置协议):** 客户端在请求 IP 时自身没有 IP 地址,无法满足 TCP 建立连接的前提条件,并且 DHCP 有广播需求、交互模式简单以及自带可靠性机制。
67+
- **物联网 (IoT) 数据上报:** 某些场景下,传感器定期上报数据,丢失个别数据点可能不影响整体趋势分析。
68+
- ......
3969

4070
### HTTP 基于 TCP 还是 UDP?
4171

docs/database/mysql/mysql-questions-01.md

+20-19
Original file line numberDiff line numberDiff line change
@@ -553,31 +553,26 @@ MVCC 在 MySQL 中实现所依赖的手段主要是: **隐藏字段、read view
553553

554554
### SQL 标准定义了哪些事务隔离级别?
555555

556-
SQL 标准定义了四个隔离级别
556+
SQL 标准定义了四种事务隔离级别,用来平衡事务的隔离性(Isolation)和并发性能。级别越高,数据一致性越好,但并发性能可能越低。这四个级别是
557557

558-
- **READ-UNCOMMITTED(读取未提交)** :最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
559-
- **READ-COMMITTED(读取已提交)** :允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。
560-
- **REPEATABLE-READ(可重复读)** :对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
558+
- **READ-UNCOMMITTED(读取未提交)** :最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。这种级别在实际应用中很少使用,因为它对数据一致性的保证太弱。
559+
- **READ-COMMITTED(读取已提交)** :允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。这是大多数数据库(如 Oracle, SQL Server)的默认隔离级别。
560+
- **REPEATABLE-READ(可重复读)** :对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。MySQL InnoDB 存储引擎的默认隔离级别正是 REPEATABLE READ。并且,InnoDB 在此级别下通过 MVCC(多版本并发控制) 和 Next-Key Locks(间隙锁+行锁) 机制,在很大程度上解决了幻读问题。
561561
- **SERIALIZABLE(可串行化)** :最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。
562562

563-
---
564-
565-
| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
566-
| :--------------: | :--: | :--------: | :--: |
567-
| READ-UNCOMMITTED ||||
568-
| READ-COMMITTED | × |||
569-
| REPEATABLE-READ | × | × ||
570-
| SERIALIZABLE | × | × | × |
571-
572-
### MySQL 的隔离级别是基于锁实现的吗?
573-
574-
MySQL 的隔离级别基于锁和 MVCC 机制共同实现的。
575-
576-
SERIALIZABLE 隔离级别是通过锁来实现的,READ-COMMITTED 和 REPEATABLE-READ 隔离级别是基于 MVCC 实现的。不过, SERIALIZABLE 之外的其他隔离级别可能也需要用到锁机制,就比如 REPEATABLE-READ 在当前读情况下需要使用加锁读来保证不会出现幻读。
563+
| 隔离级别 | 脏读 (Dirty Read) | 不可重复读 (Non-Repeatable Read) | 幻读 (Phantom Read) |
564+
| ---------------- | ----------------- | -------------------------------- | ---------------------- |
565+
| READ UNCOMMITTED ||||
566+
| READ COMMITTED | × |||
567+
| REPEATABLE READ | × | × | √ (标准) / ≈× (InnoDB) |
568+
| SERIALIZABLE | × | × | × |
577569

578570
### MySQL 的默认隔离级别是什么?
579571

580-
MySQL InnoDB 存储引擎的默认支持的隔离级别是 **REPEATABLE-READ(可重读)**。我们可以通过`SELECT @@tx_isolation;`命令来查看,MySQL 8.0 该命令改为`SELECT @@transaction_isolation;`
572+
MySQL InnoDB 存储引擎的默认隔离级别是 **REPEATABLE READ**。可以通过以下命令查看:
573+
574+
- MySQL 8.0 之前:`SELECT @@tx_isolation;`
575+
- MySQL 8.0 及之后:`SELECT @@transaction_isolation;`
581576

582577
```sql
583578
mysql> SELECT @@tx_isolation;
@@ -590,6 +585,12 @@ mysql> SELECT @@tx_isolation;
590585

591586
关于 MySQL 事务隔离级别的详细介绍,可以看看我写的这篇文章:[MySQL 事务隔离级别详解](./transaction-isolation-level.md)
592587

588+
### MySQL 的隔离级别是基于锁实现的吗?
589+
590+
MySQL 的隔离级别基于锁和 MVCC 机制共同实现的。
591+
592+
SERIALIZABLE 隔离级别是通过锁来实现的,READ-COMMITTED 和 REPEATABLE-READ 隔离级别是基于 MVCC 实现的。不过, SERIALIZABLE 之外的其他隔离级别可能也需要用到锁机制,就比如 REPEATABLE-READ 在当前读情况下需要使用加锁读来保证不会出现幻读。
593+
593594
## MySQL 锁
594595

595596
锁是一种常见的并发事务的控制方式。

docs/database/mysql/transaction-isolation-level.md

+28-25
Original file line numberDiff line numberDiff line change
@@ -11,43 +11,46 @@ tag:
1111

1212
## 事务隔离级别总结
1313

14-
SQL 标准定义了四个隔离级别
14+
SQL 标准定义了四种事务隔离级别,用来平衡事务的隔离性(Isolation)和并发性能。级别越高,数据一致性越好,但并发性能可能越低。这四个级别是
1515

16-
- **READ-UNCOMMITTED(读取未提交)** :最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。
17-
- **READ-COMMITTED(读取已提交)** :允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。
18-
- **REPEATABLE-READ(可重复读)** :对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。
16+
- **READ-UNCOMMITTED(读取未提交)** :最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。这种级别在实际应用中很少使用,因为它对数据一致性的保证太弱。
17+
- **READ-COMMITTED(读取已提交)** :允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生。这是大多数数据库(如 Oracle, SQL Server)的默认隔离级别。
18+
- **REPEATABLE-READ(可重复读)** :对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。MySQL InnoDB 存储引擎的默认隔离级别正是 REPEATABLE READ。并且,InnoDB 在此级别下通过 MVCC(多版本并发控制) 和 Next-Key Locks(间隙锁+行锁) 机制,在很大程度上解决了幻读问题。
1919
- **SERIALIZABLE(可串行化)** :最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。
2020

21-
---
21+
| 隔离级别 | 脏读 (Dirty Read) | 不可重复读 (Non-Repeatable Read) | 幻读 (Phantom Read) |
22+
| ---------------- | ----------------- | -------------------------------- | ---------------------- |
23+
| READ UNCOMMITTED ||||
24+
| READ COMMITTED | × |||
25+
| REPEATABLE READ | × | × | √ (标准) / ≈× (InnoDB) |
26+
| SERIALIZABLE | × | × | × |
2227

23-
| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
24-
| :--------------: | :--: | :--------: | :--: |
25-
| READ-UNCOMMITTED ||||
26-
| READ-COMMITTED | × |||
27-
| REPEATABLE-READ | × | × ||
28-
| SERIALIZABLE | × | × | × |
28+
**默认级别查询:**
2929

30-
MySQL InnoDB 存储引擎的默认支持的隔离级别是 **REPEATABLE-READ(可重读)**我们可以通过`SELECT @@tx_isolation;`命令来查看,MySQL 8.0 该命令改为`SELECT @@transaction_isolation;`
30+
MySQL InnoDB 存储引擎的默认隔离级别是 **REPEATABLE READ**可以通过以下命令查看:
3131

32-
```sql
33-
MySQL> SELECT @@tx_isolation;
34-
+-----------------+
35-
| @@tx_isolation |
36-
+-----------------+
37-
| REPEATABLE-READ |
38-
+-----------------+
32+
- MySQL 8.0 之前:`SELECT @@tx_isolation;`
33+
- MySQL 8.0 及之后:`SELECT @@transaction_isolation;`
34+
35+
```bash
36+
mysql> SELECT @@transaction_isolation;
37+
+-------------------------+
38+
| @@transaction_isolation |
39+
+-------------------------+
40+
| REPEATABLE-READ |
41+
+-------------------------+
3942
```
4043

41-
从上面对 SQL 标准定义了四个隔离级别的介绍可以看出,标准的 SQL 隔离级别定义里,REPEATABLE-READ(可重复读)是不可以防止幻读的。
44+
**InnoDB 的 REPEATABLE READ 对幻读的处理:**
4245

43-
但是!InnoDB 实现的 REPEATABLE-READ 隔离级别其实是可以解决幻读问题发生的,主要有下面两种情况
46+
标准的 SQL 隔离级别定义里,REPEATABLE READ 是无法防止幻读的。但 InnoDB 的实现通过以下机制很大程度上避免了幻读
4447

45-
- **快照读**:由 MVCC 机制来保证不出现幻读
46-
- **当前读**使用 Next-Key Lock 进行加锁来保证不出现幻读,Next-Key Lock 是行锁(Record Lock)和间隙锁(Gap Lock)的结合,行锁只能锁住已经存在的行,为了避免插入新行,需要依赖间隙锁
48+
- **快照读 (Snapshot Read)**:普通的 SELECT 语句,通过 **MVCC** 机制实现。事务启动时创建一个数据快照,后续的快照读都读取这个版本的数据,从而避免了看到其他事务新插入的行(幻读)或修改的行(不可重复读)
49+
- **当前读 (Current Read)**:像 `SELECT ... FOR UPDATE`, `SELECT ... LOCK IN SHARE MODE`, `INSERT`, `UPDATE`, `DELETE` 这些操作。InnoDB 使用 **Next-Key Lock** 来锁定扫描到的索引记录及其间的范围(间隙),防止其他事务在这个范围内插入新的记录,从而避免幻读。Next-Key Lock 是行锁(Record Lock)和间隙锁(Gap Lock)的组合
4750

48-
因为隔离级别越低,事务请求的锁越少,所以大部分数据库系统的隔离级别都是 **READ-COMMITTED** ,但是你要知道的是 InnoDB 存储引擎默认使用 **REPEATABLE-READ** 并不会有任何性能损失
51+
值得注意的是,虽然通常认为隔离级别越高、并发性越差,但 InnoDB 存储引擎通过 MVCC 机制优化了 REPEATABLE READ 级别。对于许多常见的只读或读多写少的场景,其性能**READ COMMITTED 相比可能没有显著差异**。不过,在写密集型且并发冲突较高的场景下,RR 的间隙锁机制可能会比 RC 带来更多的锁等待
4952

50-
InnoDB 存储引擎在分布式事务的情况下一般会用到 SERIALIZABLE 隔离级别
53+
此外,在某些特定场景下,如需要严格一致性的分布式事务(XA Transactions),InnoDB 可能要求或推荐使用 SERIALIZABLE 隔离级别来确保全局数据的一致性
5154

5255
《MySQL 技术内幕:InnoDB 存储引擎(第 2 版)》7.7 章这样写到:
5356

0 commit comments

Comments
 (0)