Skip to content

Commit 6a41900

Browse files
committed
增加锁,日志等内容
1 parent 778503f commit 6a41900

File tree

5 files changed

+50
-0
lines changed

5 files changed

+50
-0
lines changed

index.adoc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ include::high-performance-index.adoc[leveloffset=+1]
2121

2222
include::query-optimization.adoc[leveloffset=+1]
2323

24+
include::redo-log.adoc[leveloffset=+1]
25+
26+
include::undo-log.adoc[leveloffset=+1]
27+
2428
include::locks.adoc[leveloffset=+1]
2529

2630
include::sharding.adoc[leveloffset=+1]

locks.adoc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,31 @@ AUTO_INCREMENT 有两种实现方式:
4848

4949
=== Record Lock
5050

51+
Record Lock 即是常说的行锁,仅仅把一条记录锁上。
52+
53+
Record Lock 有 S 锁 和 X 锁之分。
54+
55+
[NOTE]
56+
====
57+
S 锁 和 X 锁类似 Java 中的 `ReadWriteLock`,其行为和 `ReentrantReadWriteLock` 几乎一模一样:读读并发、读写互斥、写写互斥。
58+
====
59+
5160
=== 间隙锁 Gap Lock
5261

62+
间隙锁主要是为了解决插入时的幻读问题。由于插入时,还没有数据记录,所以,无法创建该数据对应的 Record Lock。所以,提出了 Gap Lock 锁。
63+
64+
Gap Lock 的作用仅仅是为了防止插入幻影记录而已。
65+
66+
给一条记录加 Gap 锁,则不允许其他事务向这条记录前面的插入新记录。为了解决之后可能插入新记录的问题,可以在索引中最后一条记录所在页面的 `Supremum` 记录(表示该页中最大的记录)上加 Gap 锁,这样就可以阻止其他事务插入新记录了。
67+
5368
=== Next-Key Lock
5469

5570
Next-Key Lock = Record Lock + Gap Lock。
5671

5772
=== 插入意向锁 Insert Intention Lock
5873

74+
在内存中生成的一个锁结构,表示有事务想在某个间隙插入新记录,但是现在处于等待状态。
75+
76+
插入意向锁并不会阻止别的事务继续获取该记录上的任何类型的锁,非常鸡肋。
77+
5978
=== 隐式锁

redo-log.adoc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[#redo]
2+
= redo 日志,说到做到
3+
4+
每条记录修改到具体数据表空间,页号,以及每个具体的值(可以是具体的指针地址,也可以是指定字段)。
5+
6+
一批 redo 日志组成一个不可分割的组;多个组对应一条 SQL 语句(比如需要页分裂的悲观插入);多个语句组成一个事务。
7+
8+
对底层页面的一次原子访问过程称为一个 Mini-Transaction,简称 MTR。多个 MTR 组成一个 block;内存中若干个连续的 block,组成一个 log buffer。
9+
10+
11+
12+

transaction.adoc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,20 @@
1616

1717
在 Read Uncommitted 级别,事务中的修改,即使没有提交,对其他事务也都是可见的。事务可以读取未提交的数据,这也被称为**脏读(Dirty Read)**。性能不会好太多,但是问题却一大堆,实际应用中一般很少使用。
1818

19+
直接读取记录的最新版本,可能出现脏读、不可重复读和幻读等现象。
20+
1921
=== Read Committed(提交读)
2022

2123
大多数数据库系统的默认隔离级别都是 Read Committed。Read Committed 满足前面提到的隔离性的简单定义:一个事务开始时,只能“看见”已经提交的事务所做的修改。换句话说:一个事务从开始直到提交之前,所做的任何修改对其他事务都是不可见的。有时也叫不可重复读(Nonrepeatable Read)。
2224

25+
在每次执行 `SELECT` 时都生成一个 ReadView,可以避免脏读,但是无法避免不可重复读和幻读。
26+
2327
=== Repeatable Read(可重复读)
2428

2529
Repeatable Read 解决了脏读的问题。但是还是无法解决领一个**幻读(Phantom Read)**问题。所谓幻读,指的是当某个事务在读取某个范围内的记录时,另外一个事务又在该范围内插入了新的记录,当之前的事务再次读取该范围的记录时,会产生幻行(Phantom Row)。InnoDB 和 XtraDB 存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)解决了幻读的问题。
2630

31+
只在第一次执行 `SELECT` 语句时,生成一个 ReadView,可以避免出现脏读、不可重复读和幻读。
32+
2733
=== Serializable(可串行化)
2834

2935
Serializable 是最高的隔离级别。它通过强制事务串行执行,避免了前面说的幻读问题。简单来说,Serializable 会在读取的每一行数据上都加锁,所以导致大量的超时和锁争用的问题。实际中,极少使用。

undo-log.adoc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[#undo]
2+
= undo 日志,后悔药
3+
4+
在更新操作时,会把旧版本写入到 undo 中,最新的记录有一个 `roll_pointer` 指针执行旧版本,各个版本的记录依次用指针链接,组成一个版本链。
5+
6+
查询时生成 ReadView,根据其中的事务 ID 去查找 undo 版本链中的数据,这就是 MVCC 的原理。
7+
8+
删除操作,是先打标;事务提交后,会有专门的清理线程来把记录删除掉。
9+

0 commit comments

Comments
 (0)