[docs update]图片转存
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 9.9 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 30 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 11 KiB |
|
@ -74,7 +74,7 @@ private:
|
|||
|
||||
**事务可见性示意图**([图源](https://leviathan.vip/2019/03/20/InnoDB%E7%9A%84%E4%BA%8B%E5%8A%A1%E5%88%86%E6%9E%90-MVCC/#MVCC-1)):
|
||||
|
||||
![trans_visible](https://leviathan.vip/2019/03/20/InnoDB%E7%9A%84%E4%BA%8B%E5%8A%A1%E5%88%86%E6%9E%90-MVCC/trans_visible.jpg)
|
||||
![trans_visible](./images/mvvc/trans_visible.png)
|
||||
|
||||
### undo-log
|
||||
|
||||
|
@ -89,17 +89,17 @@ private:
|
|||
|
||||
**`insert` 时的数据初始状态:**
|
||||
|
||||
![](https://ddmcc-1255635056.file.myqcloud.com/317e91e1-1ee1-42ad-9412-9098d5c6a9ad.png)
|
||||
![](./images/mvvc/317e91e1-1ee1-42ad-9412-9098d5c6a9ad.png)
|
||||
|
||||
2. **`update undo log`** :`update` 或 `delete` 操作中产生的 `undo log`。该 `undo log`可能需要提供 `MVCC` 机制,因此不能在事务提交时就进行删除。提交时放入 `undo log` 链表,等待 `purge线程` 进行最后的删除
|
||||
|
||||
**数据第一次被修改时:**
|
||||
|
||||
![](https://ddmcc-1255635056.file.myqcloud.com/c52ff79f-10e6-46cb-b5d4-3c9cbcc1934a.png)
|
||||
![](./images/mvvc/c52ff79f-10e6-46cb-b5d4-3c9cbcc1934a.png)
|
||||
|
||||
**数据第二次被修改时:**
|
||||
|
||||
![](https://ddmcc-1255635056.file.myqcloud.com/6a276e7a-b0da-4c7b-bdf7-c0c7b7b3b31c.png)
|
||||
![](./images/mvvc/6a276e7a-b0da-4c7b-bdf7-c0c7b7b3b31c.png)
|
||||
|
||||
不同事务或者相同事务的对同一记录行的修改,会使该记录行的 `undo log` 成为一条链表,链首就是最新的记录,链尾就是最早的旧记录。
|
||||
|
||||
|
@ -107,9 +107,9 @@ private:
|
|||
|
||||
在 `InnoDB` 存储引擎中,创建一个新事务后,执行每个 `select` 语句前,都会创建一个快照(Read View),**快照中保存了当前数据库系统中正处于活跃(没有 commit)的事务的 ID 号**。其实简单的说保存的是系统中当前不应该被本事务看到的其他事务 ID 列表(即 m_ids)。当用户在这个事务中要读取某个记录行的时候,`InnoDB` 会将该记录行的 `DB_TRX_ID` 与 `Read View` 中的一些变量及当前事务 ID 进行比较,判断是否满足可见性条件
|
||||
|
||||
[具体的比较算法](https://github.com/facebook/mysql-8.0/blob/8.0/storage/innobase/include/read0types.h#L161)如下:[图源](https://leviathan.vip/2019/03/20/InnoDB%E7%9A%84%E4%BA%8B%E5%8A%A1%E5%88%86%E6%9E%90-MVCC/#MVCC-1)
|
||||
[具体的比较算法](https://github.com/facebook/mysql-8.0/blob/8.0/storage/innobase/include/read0types.h#L161)如下([图源](https://leviathan.vip/2019/03/20/InnoDB%E7%9A%84%E4%BA%8B%E5%8A%A1%E5%88%86%E6%9E%90-MVCC/#MVCC-1)):
|
||||
|
||||
![](https://ddmcc-1255635056.file.myqcloud.com/8778836b-34a8-480b-b8c7-654fe207a8c2.png)
|
||||
![](./images/mvvc/8778836b-34a8-480b-b8c7-654fe207a8c2.png)
|
||||
|
||||
1. 如果记录 DB_TRX_ID < m_up_limit_id,那么表明最新修改该行的事务(DB_TRX_ID)在当前事务创建快照之前就提交了,所以该记录行的值对当前事务是可见的
|
||||
|
||||
|
@ -138,13 +138,13 @@ private:
|
|||
|
||||
举个例子:
|
||||
|
||||
![](https://ddmcc-1255635056.file.myqcloud.com/6fb2b9a1-5f14-4dec-a797-e4cf388ed413.png)
|
||||
![](./images/mvvc/6fb2b9a1-5f14-4dec-a797-e4cf388ed413.png)
|
||||
|
||||
### 在 RC 下 ReadView 生成情况
|
||||
|
||||
1. **`假设时间线来到 T4 ,那么此时数据行 id = 1 的版本链为`:**
|
||||
**1. 假设时间线来到 T4 ,那么此时数据行 id = 1 的版本链为:**
|
||||
|
||||
![](https://ddmcc-1255635056.file.myqcloud.com/a3fd1ec6-8f37-42fa-b090-7446d488fd04.png)
|
||||
![](./images/mvvc/a3fd1ec6-8f37-42fa-b090-7446d488fd04.png)
|
||||
|
||||
由于 RC 级别下每次查询都会生成`Read View` ,并且事务 101、102 并未提交,此时 `103` 事务生成的 `Read View` 中活跃的事务 **`m_ids` 为:[101,102]** ,`m_low_limit_id`为:104,`m_up_limit_id`为:101,`m_creator_trx_id` 为:103
|
||||
|
||||
|
@ -152,9 +152,9 @@ private:
|
|||
- 根据 `DB_ROLL_PTR` 找到 `undo log` 中的上一版本记录,上一条记录的 `DB_TRX_ID` 还是 101,不可见
|
||||
- 继续找上一条 `DB_TRX_ID`为 1,满足 1 < m_up_limit_id,可见,所以事务 103 查询到数据为 `name = 菜花`
|
||||
|
||||
2. **`时间线来到 T6 ,数据的版本链为`:**
|
||||
**2. 时间线来到 T6 ,数据的版本链为:**
|
||||
|
||||
![markdown](https://ddmcc-1255635056.file.myqcloud.com/528559e9-dae8-4d14-b78d-a5b657c88391.png)
|
||||
![](./images/mvvc/528559e9-dae8-4d14-b78d-a5b657c88391.png)
|
||||
|
||||
因为在 RC 级别下,重新生成 `Read View`,这时事务 101 已经提交,102 并未提交,所以此时 `Read View` 中活跃的事务 **`m_ids`:[102]** ,`m_low_limit_id`为:104,`m_up_limit_id`为:102,`m_creator_trx_id`为:103
|
||||
|
||||
|
@ -162,9 +162,9 @@ private:
|
|||
|
||||
- 根据 `DB_ROLL_PTR` 找到 `undo log` 中的上一版本记录,上一条记录的 `DB_TRX_ID` 为 101,满足 101 < m_up_limit_id,记录可见,所以在 `T6` 时间点查询到数据为 `name = 李四`,与时间 T4 查询到的结果不一致,不可重复读!
|
||||
|
||||
3. **`时间线来到 T9 ,数据的版本链为`:**
|
||||
**3. 时间线来到 T9 ,数据的版本链为:**
|
||||
|
||||
![markdown](https://ddmcc-1255635056.file.myqcloud.com/6f82703c-36a1-4458-90fe-d7f4edbac71a.png)
|
||||
![](./images/mvvc/6f82703c-36a1-4458-90fe-d7f4edbac71a.png)
|
||||
|
||||
重新生成 `Read View`, 这时事务 101 和 102 都已经提交,所以 **m_ids** 为空,则 m_up_limit_id = m_low_limit_id = 104,最新版本事务 ID 为 102,满足 102 < m_low_limit_id,可见,查询结果为 `name = 赵六`
|
||||
|
||||
|
@ -172,11 +172,11 @@ private:
|
|||
|
||||
### 在 RR 下 ReadView 生成情况
|
||||
|
||||
**在可重复读级别下,只会在事务开始后第一次读取数据时生成一个 Read View(m_ids 列表)**
|
||||
在可重复读级别下,只会在事务开始后第一次读取数据时生成一个 Read View(m_ids 列表)
|
||||
|
||||
1. **`在 T4 情况下的版本链为`:**
|
||||
**1. 在 T4 情况下的版本链为:**
|
||||
|
||||
![markdown](https://ddmcc-1255635056.file.myqcloud.com/0e906b95-c916-4f30-beda-9cb3e49746bf.png)
|
||||
![](./images/mvvc/0e906b95-c916-4f30-beda-9cb3e49746bf.png)
|
||||
|
||||
在当前执行 `select` 语句时生成一个 `Read View`,此时 **`m_ids`:[101,102]** ,`m_low_limit_id`为:104,`m_up_limit_id`为:101,`m_creator_trx_id` 为:103
|
||||
|
||||
|
@ -186,11 +186,11 @@ private:
|
|||
- 根据 `DB_ROLL_PTR` 找到 `undo log` 中的上一版本记录,上一条记录的 `DB_TRX_ID` 还是 101,不可见
|
||||
- 继续找上一条 `DB_TRX_ID`为 1,满足 1 < m_up_limit_id,可见,所以事务 103 查询到数据为 `name = 菜花`
|
||||
|
||||
2. **`时间点 T6 情况下`:**
|
||||
**2. 时间点 T6 情况下:**
|
||||
|
||||
![markdown](https://ddmcc-1255635056.file.myqcloud.com/79ed6142-7664-4e0b-9023-cf546586aa39.png)
|
||||
![](./images/mvvc/79ed6142-7664-4e0b-9023-cf546586aa39.png)
|
||||
|
||||
在 RR 级别下只会生成一次`Read View`,所以此时依然沿用 **`m_ids` :[101,102]** ,`m_low_limit_id`为:104,`m_up_limit_id`为:101,`m_creator_trx_id` 为:103
|
||||
在 RR 级别下只会生成一次`Read View`,所以此时依然沿用 **`m_ids` :[101,102]** ,`m_low_limit_id`为:104,`m_up_limit_id`为:101,`m_creator_trx_id` 为:103
|
||||
|
||||
- 最新记录的 `DB_TRX_ID` 为 102,m_up_limit_id <= 102 < m_low_limit_id,所以要在 `m_ids` 列表中查找,发现 `DB_TRX_ID` 存在列表中,那么这个记录不可见
|
||||
|
||||
|
@ -200,9 +200,9 @@ private:
|
|||
|
||||
- 继续找上一条 `DB_TRX_ID`为 1,满足 1 < m_up_limit_id,可见,所以事务 103 查询到数据为 `name = 菜花`
|
||||
|
||||
3. **时间点 T9 情况下:**
|
||||
**3. 时间点 T9 情况下:**
|
||||
|
||||
![markdown](https://ddmcc-1255635056.file.myqcloud.com/cbbedbc5-0e3c-4711-aafd-7f3d68a4ed4e.png)
|
||||
![](./images/mvvc/cbbedbc5-0e3c-4711-aafd-7f3d68a4ed4e.png)
|
||||
|
||||
此时情况跟 T6 完全一样,由于已经生成了 `Read View`,此时依然沿用 **`m_ids` :[101,102]** ,所以查询结果依然是 `name = 菜花`
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ tag:
|
|||
|
||||
**索引是一种用于快速查询和检索数据的数据结构。常见的索引结构有: B 树, B+树和 Hash。**
|
||||
|
||||
索引的作用就相当于目录的作用。打个比方: 我们在查字典的时候,如果没有目录,那我们就只能一页一页的去找我们需要查的那个字,速度很慢。如果有目录了,我们只需要先去目录里查找字的位置,然后直接翻到那一页就行了。
|
||||
索引的作用就相当于书的目录。打个比方: 我们在查字典的时候,如果没有目录,那我们就只能一页一页的去找我们需要查的那个字,速度很慢。如果有目录了,我们只需要先去目录里查找字的位置,然后直接翻到那一页就行了。
|
||||
|
||||
## 索引的优缺点
|
||||
|
||||
|
@ -179,8 +179,7 @@ SELECT id FROM table WHERE id=1;
|
|||
|
||||
如果一个索引包含(或者说覆盖)所有需要查询的字段的值,我们就称之为“覆盖索引”。我们知道在 InnoDB 存储引擎中,如果不是主键索引,叶子节点存储的是主键+列值。最终还是要“回表”,也就是要通过主键再查找一次。这样就会比较慢覆盖索引就是把要查询出的列和索引是对应的,不做回表操作!
|
||||
|
||||
**覆盖索引即需要查询的字段正好是索引的字段,那么直接根据该索引,就可以查到数据了,
|
||||
而无需回表查询。**
|
||||
**覆盖索引即需要查询的字段正好是索引的字段,那么直接根据该索引,就可以查到数据了,而无需回表查询。**
|
||||
|
||||
> 如主键索引,如果一条 SQL 需要查询主键,那么正好根据主键索引就可以查到主键。
|
||||
>
|
||||
|
|
|
@ -317,7 +317,7 @@ mysql> SELECT @@tx_isolation;
|
|||
+-----------------+
|
||||
```
|
||||
|
||||
关于 MySQL 事务的详细介绍,可以看看我写的这篇文章:[MySQL 事务隔离级别详解](https://javaguide.cn/database/mysql/transaction-isolation-level.html)。
|
||||
关于 MySQL 事务隔离级别的详细介绍,可以看看我写的这篇文章:[MySQL 事务隔离级别详解](https://javaguide.cn/database/mysql/transaction-isolation-level.html)。
|
||||
|
||||
## MySQL 锁
|
||||
|
||||
|
@ -325,7 +325,7 @@ mysql> SELECT @@tx_isolation;
|
|||
|
||||
MyISAM 仅仅支持表级锁(table-level locking),一锁就锁整张表,这在并发写的情况下性非常差。
|
||||
|
||||
InnoDB 不光支持表级锁(table-level locking),还支持行级锁(row-level locking),默认为行级锁。行级锁的粒度更小,仅对相关的记录上锁即可(对一行或者多行记录加锁),所以对于并发写入操作来说 InnoDB 的性能更高。
|
||||
InnoDB 不光支持表级锁(table-level locking),还支持行级锁(row-level locking),默认为行级锁。行级锁的粒度更小,仅对相关的记录上锁即可(对一行或者多行记录加锁),所以对于并发写入操作来说, InnoDB 的性能更高。
|
||||
|
||||
**表级锁和行级锁对比** :
|
||||
|
||||
|
|
|
@ -174,7 +174,7 @@ protostuff 基于 Google protobuf,但是提供了更多的功能和更简易
|
|||
|
||||
Github 地址:[https://github.com/protostuff/protostuff](https://github.com/protostuff/protostuff)。
|
||||
|
||||
### hession
|
||||
### hessian
|
||||
|
||||
hessian 是一个轻量级的,自定义描述的二进制 RPC 协议。hessian 是一个比较老的序列化实现了,并且同样也是跨语言的。
|
||||
|
||||
|
|