+
+在 MySQL 8.0 上实际执行:事务 103 未提交时,可重复读的读事务读到 'b';103 提交之后,这个读事务再读仍然是 'b',而新开始的提交读事务读到 'c'。
### 快照读与当前读
@@ -323,11 +351,11 @@ UPDATE;
DELETE;
```
-在进行 SELECT 操作时,可以强制指定进行加锁操作。以下第一个语句需要加 S 锁,第二个需要加 X 锁。
+在进行 SELECT 操作时,可以强制指定进行加锁操作。以下第一个语句需要加 S 锁,第二个需要加 X 锁。MySQL 8.0 起推荐用 FOR SHARE 代替 LOCK IN SHARE MODE。
```sql
-SELECT * FROM table WHERE ? lock in share mode;
-SELECT * FROM table WHERE ? for update;
+SELECT * FROM table WHERE ? FOR SHARE;
+SELECT * FROM table WHERE ? FOR UPDATE;
```
## 六、Next-Key Locks
@@ -336,6 +364,18 @@ Next-Key Locks 是 MySQL 的 InnoDB 存储引擎的一种锁实现。
在可重复读(REPEATABLE READ)隔离级别下,MVCC 使普通的 SELECT(快照读)不会读到其它事务新插入的行,但是 UPDATE、DELETE、SELECT ... FOR UPDATE 等当前读仍然可能出现幻读,Next-Key Locks 就是为了解决这个问题而存在的。InnoDB 使用 MVCC + Next-Key Locks 在可重复读隔离级别下解决了幻读问题。
+需要注意的是,这要求一个事务中的读取全部是快照读或者全部是当前读,两者混用时仍然会出现幻读。在 MySQL 8.0 中实测,表 acct 原有 id 为 1、2 的两行:
+
+```text
+A:SELECT * FROM acct WHERE balance >= 100; -- id 1、2
+B:INSERT INTO acct VALUES (3, 100); -- 自动提交
+A:SELECT * FROM acct WHERE balance >= 100; -- 仍然是 id 1、2
+A:UPDATE acct SET balance = balance + 10 WHERE balance >= 100; -- Rows matched: 3
+A:SELECT * FROM acct WHERE balance >= 100; -- id 1、2、3
+```
+
+事务 A 的 UPDATE 是当前读,看到了事务 B 新插入并已提交的第 3 行,并且修改了它;这一行最新版本的事务 ID 变成了 A 自己,所以之后的快照读也能看到它。如果 A 一开始就用 SELECT ... FOR UPDATE 加锁读取,B 的插入会被 Next-Key Locks 阻塞,直到锁等待超时(ERROR 1205 Lock wait timeout exceeded)。
+
### Record Locks
锁定一个记录上的索引,而不是记录本身。
@@ -362,7 +402,11 @@ SELECT c FROM t WHERE c BETWEEN 10 and 20 FOR UPDATE;
(20, +∞)
```
-
+在 MySQL 8.0 中建表 t(id, c),c 上有普通索引,插入 c 为 10、11、13、20 的四行,然后在可重复读下执行两种加锁读,从 performance_schema.data_locks 中查看实际加的锁,并在另一个事务中尝试插入:
+
+
+
+按 c = 11 查询时,c 不是唯一索引,后面还可能有 c = 11 的记录,所以除了 (10, 11] 的 Next-Key Lock,还要锁住到下一条记录 13 之间的间隙;如果 c 是唯一索引,就只锁 c = 11 这一条记录。
## 七、关系数据库设计理论
@@ -526,8 +570,11 @@ Entity-Relationship,有三个组成部分:实体、属性、联系。
- 施瓦茨. 高性能 MYSQL(第3版)[M]. 电子工业出版社, 2013.
- 史嘉权. 数据库系统概论[M]. 清华大学出版社有限公司, 2006.
- [The InnoDB Storage Engine](https://dev.mysql.com/doc/refman/5.7/en/innodb-storage-engine.html)
+- [MySQL 8.0: Transaction Isolation Levels](https://dev.mysql.com/doc/refman/8.0/en/innodb-transaction-isolation-levels.html)
+- [MySQL 8.0: InnoDB Locking](https://dev.mysql.com/doc/refman/8.0/en/innodb-locking.html)
+- [MySQL 8.0: The data_locks Table](https://dev.mysql.com/doc/refman/8.0/en/performance-schema-data-locks-table.html)
- [Transaction isolation levels](https://www.slideshare.net/ErnestoHernandezRodriguez/transaction-isolation-levels)
-- [Concurrency Control](http://scanftree.com/dbms/2-phase-locking-protocol)
+- [Concurrency Control](https://web.archive.org/web/20260614192237/https://scanftree.com/dbms/2-phase-locking-protocol)
- [The Nightmare of Locking, Blocking and Isolation Levels!](https://www.slideshare.net/brshristov/the-nightmare-of-locking-blocking-and-isolation-levels-46391666)
- [Database Normalization and Normal Forms with an Example](https://aksakalli.github.io/2012/03/12/database-normalization-and-normal-forms-with-an-example.html)
- [The basics of the InnoDB undo logging and history system](https://blog.jcole.us/2014/04/16/the-basics-of-the-innodb-undo-logging-and-history-system/)
diff --git a/tools/diagram/src/acid.svg b/tools/diagram/src/acid.svg
new file mode 100644
index 00000000..e4227499
--- /dev/null
+++ b/tools/diagram/src/acid.svg
@@ -0,0 +1,58 @@
+
diff --git a/tools/diagram/src/lock-level-1.svg b/tools/diagram/src/lock-level-1.svg
new file mode 100644
index 00000000..c174f861
--- /dev/null
+++ b/tools/diagram/src/lock-level-1.svg
@@ -0,0 +1,61 @@
+
diff --git a/tools/diagram/src/lock-level-2.svg b/tools/diagram/src/lock-level-2.svg
new file mode 100644
index 00000000..478ff3ed
--- /dev/null
+++ b/tools/diagram/src/lock-level-2.svg
@@ -0,0 +1,56 @@
+
diff --git a/tools/diagram/src/lock-level-3.svg b/tools/diagram/src/lock-level-3.svg
new file mode 100644
index 00000000..60c86a6c
--- /dev/null
+++ b/tools/diagram/src/lock-level-3.svg
@@ -0,0 +1,59 @@
+
diff --git a/tools/diagram/src/mvcc-readview.svg b/tools/diagram/src/mvcc-readview.svg
new file mode 100644
index 00000000..316238c0
--- /dev/null
+++ b/tools/diagram/src/mvcc-readview.svg
@@ -0,0 +1,76 @@
+
diff --git a/tools/diagram/src/mvcc-undo-chain.svg b/tools/diagram/src/mvcc-undo-chain.svg
new file mode 100644
index 00000000..5a9c4c47
--- /dev/null
+++ b/tools/diagram/src/mvcc-undo-chain.svg
@@ -0,0 +1,91 @@
+
diff --git a/tools/diagram/src/next-key-locks-v2.svg b/tools/diagram/src/next-key-locks-v2.svg
new file mode 100644
index 00000000..68de180a
--- /dev/null
+++ b/tools/diagram/src/next-key-locks-v2.svg
@@ -0,0 +1,79 @@
+
diff --git a/tools/diagram/src/txn-dirty-read.svg b/tools/diagram/src/txn-dirty-read.svg
new file mode 100644
index 00000000..48e30065
--- /dev/null
+++ b/tools/diagram/src/txn-dirty-read.svg
@@ -0,0 +1,57 @@
+
diff --git a/tools/diagram/src/txn-flow.svg b/tools/diagram/src/txn-flow.svg
new file mode 100644
index 00000000..7971e308
--- /dev/null
+++ b/tools/diagram/src/txn-flow.svg
@@ -0,0 +1,62 @@
+
diff --git a/tools/diagram/src/txn-lost-update.svg b/tools/diagram/src/txn-lost-update.svg
new file mode 100644
index 00000000..4d0ef578
--- /dev/null
+++ b/tools/diagram/src/txn-lost-update.svg
@@ -0,0 +1,63 @@
+
diff --git a/tools/diagram/src/txn-non-repeatable.svg b/tools/diagram/src/txn-non-repeatable.svg
new file mode 100644
index 00000000..d309655c
--- /dev/null
+++ b/tools/diagram/src/txn-non-repeatable.svg
@@ -0,0 +1,58 @@
+
diff --git a/tools/diagram/src/txn-phantom.svg b/tools/diagram/src/txn-phantom.svg
new file mode 100644
index 00000000..4f783d82
--- /dev/null
+++ b/tools/diagram/src/txn-phantom.svg
@@ -0,0 +1,58 @@
+