B站视频相关-2

我爱海鲸 2025-11-20 21:02:56 暂无标签

简介面试、mysql

1、Java高频面试之MySQL 的 MVCC 是怎么实现的?涉及哪些隐藏字段?_哔哩哔哩_bilibili

# MySQL InnoDB MVCC实现原理详解

## 一、什么是MVCC?

MVCC(Multi-Version Concurrency Control,多版本并发控制)是InnoDB存储引擎用来解决事务并发冲突导致的数据一致性问题的核心解决方案。它通过数据的版本号机制来保证事务能够看到一致的数据视图,从而在保证数据一致性的同时,提高并发性能。

## 二、MVCC的核心实现机制

### 2.1 三个隐藏字段

InnoDB为了实现MVCC,在每行数据中维护了三个隐藏字段:

1. **DB_ROW_ID(行ID)**
   - 当表没有显式声明主键时,InnoDB会自动生成一个隐藏的列作为聚集索引
   - 用于唯一标识表中的每一行数据

2. **TRX_ID(事务ID)**
   - 记录数据最后一次被修改的事务ID
   - 用于标识该行数据是由哪个事务创建的或最后一次修改的

3. **ROLL_PTR(回滚指针)**
   - 指向这行数据对应在UndoLog(回滚日志)中的上一个数据版本
   - 通过这个指针可以形成数据的版本链,追溯历史版本

### 2.2 版本链的形成

通过ROLL_PTR指针,InnoDB可以将同一行数据的不同版本连接成一个链表,形成版本链。每个版本都记录了创建它的事务ID(TRX_ID),这样就能追溯到数据的完整历史。

## 三、快照读与ReadView

### 3.1 快照读(Snapshot Read)

当事务执行SELECT快照读时,InnoDB会根据当前事务的隔离级别和一致性视图,沿着版本链去找到符合可见性规则的记录版本。

### 3.2 ReadView(读视图)

ReadView是MVCC实现可见性判断的关键机制:

- **创建时机**:事务执行快照读时,会对这个记录创建一个ReadView视图
- **记录内容**:ReadView会记录当前活跃事务(即未提交的事务)的ID列表
- **作用**:用于判断数据版本对当前事务是否可见

### 3.3 可见性判断规则

可见性算法规则的核心是:将当前被修改的数据最新记录中的TRX_ID和ReadView里面活跃事务ID进行比较。

**数据版本对当前事务可见的条件:**
- 记录的TRX_ID小于ReadView中的最小活跃事务ID,或者
- 记录的TRX_ID属于当前事务版本

只有满足上述条件的数据版本,才对当前事务可见。

## 四、MVCC的优势

1. **提高并发性能**:读操作不需要加锁,避免了读写冲突
2. **保证数据一致性**:通过版本链和ReadView机制,确保事务看到一致的数据视图
3. **支持多版本**:同一行数据可以存在多个版本,满足不同事务的读取需求

## 五、总结

MVCC是InnoDB实现高并发和事务隔离的核心机制。它通过三个隐藏字段(DB_ROW_ID、TRX_ID、ROLL_PTR)构建版本链,结合ReadView机制实现数据的可见性判断,从而在保证数据一致性的同时,大幅提升了数据库的并发处理能力。

理解MVCC的实现原理,对于深入掌握MySQL的事务隔离级别、解决并发问题以及进行性能优化都具有重要意义。

2、阿里面试之MVCC过程中会加锁吗?【Java高频面试】_哔哩哔哩_bilibili

# MVCC机制中加锁问题深度解析

## 一、问题背景

在面试中,经常会被问到:"**MVCC过程中会加锁吗?**"这个问题看似简单,实际上考察的是对MVCC机制底层设计方案的深入理解。

MVCC(Multi-Version Concurrency Control,多版本并发控制)是确保在高并发下,多个事务读取数据的时候不加锁也可以保证多次读取相同的一个值。MVCC在**读已提交(Read Committed)**以及**可重复读(Repeatable Read)**的隔离级别下发挥作用,可以解决脏读、不可重复读的问题。

## 二、核心问题:MVCC是否需要加锁?

### 2.1 核心思想

MVCC的核心思想是**减少锁定**,通过多版本并发控制来避免大部分锁的竞争,从而提高并发性能。

## 三、分情况讨论

### 3.1 读操作:通常不需要加锁

在MVCC中,**读操作通常不需要加锁**来控制并发访问。相反,每个事务都可以读取到自己事务的快照,而不需要共享锁和排他锁。

**工作原理:**
- 每个事务在执行SELECT快照读时,会读取到符合自己事务可见性的数据版本
- 通过ReadView机制判断数据版本是否可见
- 多个事务可以同时读取不同版本的数据,互不干扰

### 3.2 写操作:使用写时复制技术

在写操作的时候,MVCC会使用一种叫**写时复制(Copy-on-Write)**的技术:

1. **复制数据**:在修改数据之前先将数据复制一份,从而创建一个新的快照
2. **版本检查**:当一个事务需要修改数据的时候,MVCC首先会检查修改数据的快照版本,是否与该事务的快照版本一致
3. **条件判断**:
   - 如果一致,则表示可以修改这条数据
   - 否则,该事务需要等待其他事务完成对该数据的修改
4. **隔离性保证**:这个事务在新快照上的修改,不会影响原始数据。其他事务可以继续读取原始数据的快照,从而解决了不可重复读的问题

**优势:**
- 读取一个数据进行修改的时候,不需要加锁也不会出现读写冲突的问题
- 多个事务可以并发读取,互不干扰

### 3.3 特殊情况:仍会使用锁

尽管MVCC的核心思想是减少锁定,但**一些数据库系统在某些情况下仍然可能会使用锁定来保证一致性**,尤其是在处理更新操作的时候。

#### 3.3.1 需要加锁的场景

1. **确保数据完整性**:在需要确保数据完整性的场景下
2. **事务提交/回滚阶段**:在事务提交或回滚操作的时候,可能会短暂地使用锁机制来保证数据的一致性

#### 3.3.2 为什么需要加锁?

虽然MVCC通过多版本并发控制来避免大部分锁的竞争,但在**事务结束阶段**,为了确保所有事务的正确提交或者回滚,这些数据库系统仍然需要通过锁定来防止其他并发的事务干扰当前事务的状态。

#### 3.3.3 锁的使用特点

- **短暂使用**:这种锁定技术通常仅在必要的时候短暂使用
- **保证ACID特性**:确保事务的原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)得到完整的保障

## 四、总结

### 4.1 核心要点

1. **读操作**:MVCC机制下,读操作通常不需要加锁,每个事务读取自己的快照版本
2. **写操作**:使用写时复制技术,通过版本检查来避免锁竞争
3. **特殊情况**:在事务提交/回滚等关键阶段,仍会短暂使用锁来保证数据一致性

### 4.2 设计理念

MVCC的设计理念是**最大化减少锁的使用**,通过多版本机制实现高并发下的数据一致性。但在保证ACID特性的关键节点,仍然需要锁机制作为最后的保障。

### 4.3 面试回答要点

回答这个问题时,需要从以下几个维度展开:

1. **核心思想**:MVCC是为了减少锁的使用
2. **读操作**:通常不加锁,通过快照读实现
3. **写操作**:使用写时复制,通过版本检查避免锁竞争
4. **特殊情况**:事务提交/回滚时仍需要锁来保证一致性
5. **平衡点**:在减少锁竞争和提高并发性能之间找到平衡

理解MVCC中加锁的机制,有助于深入掌握数据库并发控制的本质,在实际开发中更好地处理并发场景。

3、【计算机】为什么MySQL不建议使用NULL作为列默认值?_哔哩哔哩_bilibili

# 数据库NULL值处理陷阱与最佳实践

## 一、问题背景

**NULL值的处理是开发人员最容易出错的地方**。主要原因是,大家习惯使用二元的布尔逻辑来思考判断,而数据库对于NULL的处理逻辑是**三值逻辑**。

NULL是一种列的特殊约束。当我们创建一个新的列的时候,如果没有明确使用关键字`NOT NULL`声明,MySQL会默认为它添加一个NULL的约束。有些开发人员在创建数据表的时候,由于懒惰直接使用MySQL的默认推荐设置,导致在使用NULL场景中得出不确定的查询结果,以及引起数据问题。

## 二、三值逻辑 vs 二值逻辑

### 2.1 二值逻辑(编程语言)

大多数编程语言都是基于**二值逻辑**,逻辑值只有**真(True)**和**假(False)**两个。

### 2.2 三值逻辑(SQL语言)

SQL语言采用一种特别的逻辑体系——**三值逻辑**,逻辑值除了真和假,还有第三个值:**不确定(Unknown)**。

### 2.3 NULL的本质

- NULL值既不是值也不是变量
- 它只是表示**没有值的标记**
- 逻辑比较只适用于值,而NULL不是值

## 三、NULL值在SQL查询中的陷阱

### 3.1 逻辑运算中的NULL

在SQL语言中,如果Unknown参与到逻辑运算中,就会存在一个**计算优先级的问题**。

**示例1:AND运算中的NULL**

假设有一张`user`表,其中`form`字段默认是NULL值,表中存在一条数据:
- `name = 'test'`
- `form = NULL`

执行这样一条SQL语句:
```sql
SELECT * FROM user WHERE name = 'test' AND form = NULL;
```

**结果:无法查询出name等于test的这些数据。**

**原因分析:**
- 这个条件相当于 `True AND Unknown`
- 在SQL的三值逻辑中,Unknown的优先级更高
- 所以结果是Unknown,而不是True

### 3.2 三值逻辑运算表

在SQL语言中,针对`NOT`、`AND`、`OR`这三类逻辑运算符,针对三值的处理逻辑有专门的运算规则。其中,浅蓝色部分是三值逻辑中独特的运算,这些在二值逻辑中是不存在的。其余的SQL逻辑谓词都能由这三个逻辑运算组合而来。

**关键发现:** 如果Unknown这个值参与到逻辑运算的时候,SQL的运行结果和预期是不一致的。

### 3.3 比较运算中的NULL

**示例2:NOT运算中的NULL**

如果我们想查询年龄等于20岁或者不等于20岁的所有用户:
```sql
SELECT * FROM user WHERE age = 20 OR age != 20;
```

如果此时有一条数据的`Age`字段为NULL,那么同样的语句是**无法把这条数据查询出来的**。

**解决方案:**
必须在后面再加一个判断:
```sql
SELECT * FROM user WHERE age = 20 OR age != 20 OR age IS NULL;
```

## 四、NULL值带来的其他问题

### 4.1 索引性能问题

假设索引列存在NULL值:
- **NULL不会被索引**,导致索引变得很稀疏
- 严重影响查询性能
- 索引的利用率降低

### 4.2 违反业务逻辑和约束

在某些情况下,如果使用NULL作为列的默认值,可能会违反业务逻辑或者数据库的约束:
- 例如:某个列不允许为空,但是我们把它的默认值设置为NULL,则可能会违反约束
- 导致数据完整性问题

## 五、最佳实践:如何避免NULL值问题

### 5.1 添加NOT NULL约束

想要解决NULL带来的各种问题,**最佳的方法应该是往表里面添加NOT NULL的约束**,来尽力去排除NULL的问题。

**优势:**
- 回到熟悉的二值逻辑运算
- 避免三值逻辑带来的意外结果
- 提高数据完整性
- 改善索引性能

### 5.2 设计建议

1. **明确列的含义**:在设计表结构时,明确每个列是否允许为空
2. **使用默认值**:对于可能为空的列,考虑使用有意义的默认值而不是NULL
3. **添加约束**:在创建表时,明确使用`NOT NULL`约束
4. **查询时注意**:如果必须使用NULL,查询时要使用`IS NULL`或`IS NOT NULL`进行判断

### 5.3 代码示例

**推荐做法:**
```sql
CREATE TABLE user (
    id INT PRIMARY KEY,
    name VARCHAR(50) NOT NULL,
    age INT NOT NULL DEFAULT 0,
    email VARCHAR(100) NOT NULL
);
```

**不推荐做法:**
```sql
CREATE TABLE user (
    id INT PRIMARY KEY,
    name VARCHAR(50),  -- 默认为NULL
    age INT,           -- 默认为NULL
    email VARCHAR(100) -- 默认为NULL
);
```

## 六、总结

### 6.1 核心要点

1. **三值逻辑陷阱**:SQL使用三值逻辑(True/False/Unknown),与编程语言的二值逻辑不同
2. **查询意外结果**:NULL值参与逻辑运算时,会导致查询结果与预期不符
3. **性能影响**:NULL值不会被索引,影响查询性能
4. **数据完整性**:NULL值可能违反业务逻辑和数据库约束

### 6.2 最佳实践

- **明确约束**:在创建表时,明确使用`NOT NULL`约束
- **使用默认值**:为可能为空的列设置有意义的默认值
- **查询注意**:如果必须处理NULL,使用`IS NULL`或`IS NOT NULL`
- **回到二值逻辑**:通过NOT NULL约束,避免三值逻辑带来的复杂性

理解NULL值的处理机制,对于编写正确的SQL查询、保证数据完整性和提升数据库性能都具有重要意义。在实际开发中,应该尽量避免使用NULL,或者明确处理NULL值的情况。

你好:我的2025

上一篇:B站视频相关-1