diff --git a/notes/数据库系统原理.md b/notes/数据库系统原理.md index ebea2700..71ae0182 100644 --- a/notes/数据库系统原理.md +++ b/notes/数据库系统原理.md @@ -14,7 +14,10 @@ * [版本号](#版本号) * [Undo 日志](#undo-日志) * [实现过程](#实现过程) -* [六、间隙锁](#六间隙锁) +* [六、Next-Key Locks](#六next-key-locks) + * [Record Locks](#record-locks) + * [Grap Locks](#grap-locks) + * [Next-Key Locks](#next-key-locks) * [七、关系数据库设计理论](#七关系数据库设计理论) * [函数依赖](#函数依赖) * [异常](#异常) @@ -211,21 +214,21 @@ lock-x(A)...unlock(A)...lock-s(B)...unlock(B)...lock-s(c)...unlock(C)... # 五、多版本并发控制 -(Multi-Version Concurrency Control, MVCC)是 MySQL 的 InnoDB 存储引擎实现隔离级别的一种具体方式,它的基本思想是通过保存每个数据行的多个版本,在并发操作控制多个事务访问某个版本,从而保证多个事务对同一个数据行读取的结果是一致的。 +(Multi-Version Concurrency Control, MVCC)是 MySQL 的 InnoDB 存储引擎实现隔离级别的一种具体方式,它的基本思想是通过保存每个数据行的多个版本,一个事务对数据行做修改时,其它事务可以读取之前的一个版本,并且都是读取相同的版本,从而保证多个事务对同一个数据行读取的结果是一致的。 InnoDB 的 MVCC 在读取和修改数据行时无需加锁,这属于乐观锁的一种实现。正因为无需加锁,因此性能上也会更好。 -InnoDB 的 MVCC 可以用于实现提交读和可重复读。未提交读总是读取最新的数据行,无需使用 MVCC;而可串行化需要对所有读取的行都加锁,单纯使用 MVCC 无法实现。 +InnoDB 的 MVCC 可以用于实现提交读和可重复读这两种隔离级别。而对于未提交读隔离级别,它总是读取最新的数据行,无需使用 MVCC;可串行化隔离级别需要对所有读取的行都加锁,单纯使用 MVCC 无法实现。 ## 版本号 - 系统版本号:是一个递增的数字,每开始一个新的事务,系统版本号就会自动递增。 - 事务版本号:事务开始时的系统版本号。 -InooDB 的 MVCC 在每行记录后面都保存着两个隐藏的列,用来存储来个版本号: +InooDB 的 MVCC 在每行记录后面都保存着两个隐藏的列,用来存储两个版本号: - 创建版本号:指示创建一个数据行的快照时的系统版本号; -- 删除版本号:如果该快照的删除版本号大于当前事务版本号表示该快照有效,否则该快照无法读取。 +- 删除版本号:如果该快照的删除版本号大于当前事务版本号表示该快照有效,否则表示该快照已经被删除了。 ## Undo 日志 @@ -241,9 +244,9 @@ InnoDB 的 MVCC 使用到的快照存储在 Undo 日志中,该日志通过回 当开始新一个事务时,该事务的版本号肯定会大于所有数据行快照的创建版本号,理解这一点很关键。 -把没对一个数据行做修改的事务称为 T1,T1 所要读取的数据行快照的创建版本号必须小于当前事务的版本号,因为如果大于或者等于当前事务的版本号,那么该数据行快照是其它事务的最新修改,因此不能去读取它。 +把没对一个数据行做修改的事务称为 T1,T1 所要读取的数据行快照的创建版本号必须小于当前事务的版本号,因为如果大于或者等于当前事务的版本号,那么表示该数据行快照是其它事务的最新修改,因此不能去读取它。 -除了上面的要求,T1 所要读取的数据行快照的删除版本号必须小于当前事务版本号,因为如果大于或者等于当前事务版本号,那么该数据行快照是已经被删除的,不应该去读取它。 +除了上面的要求,T1 所要读取的数据行快照的删除版本号必须小于当前事务版本号,因为如果大于或者等于当前事务版本号,那么表示该数据行快照是已经被删除的,不应该去读取它。 ### 2. INSERT @@ -257,7 +260,49 @@ InnoDB 的 MVCC 使用到的快照存储在 Undo 日志中,该日志通过回 将系统版本号作为更新后的数据行快照的创建版本号,同时将系统版本号作为作为更新前的数据行快照的删除版本号。可以理解为新执行 DELETE 后执行 INSERT。 -# 六、间隙锁 +# 六、Next-Key Locks + +以下内容都是针对 MySQL 的 InnoDB 存储引擎来讨论的。 + +和 MVCC 一样,Next-Key Locks 也是一种实现隔离级别的一种方式。相比于 MVCC,它可以解决幻读问题。 + +## Record Locks + +锁定的对象时索引,而不是数据。如果表没有设置索引,InnoDB 会自动在主键上创建隐藏的聚集索引,因此 Record Lock 依然可以使用。 + +## Grap Locks + +锁定一个范围内的索引,例如当一个事务执行以下语句,其它事务就不能在 t.c1 中插入 15。 + +```sql +SELECT c1 FROM t WHERE c1 BETWEEN 10 and 20 FOR UPDATE; +``` + +## Next-Key Locks + +它是 Record Locks 和 Gap Locks 的结合。在 user 中有以下记录: + +```sql +| id | last_name | first_name | age | +|------|-------------|--------------|-------| +| 4 | stark | tony | 21 | +| 1 | tom | hiddleston | 30 | +| 3 | morgan | freeman | 40 | +| 5 | jeff | dean | 50 | +| 2 | donald | trump | 80 | ++------|-------------|--------------|-------+ +``` + +那么就需要锁定以下范围: + +```sql +(-∞, 21] +(21, 30] +(30, 40] +(40, 50] +(50, 80] +(80, ∞) +``` # 七、关系数据库设计理论 @@ -499,3 +544,5 @@ Entity-Relationship,有三个组成部分:实体、属性、联系。 - [三级模式与两级映像](http://blog.csdn.net/d2457638978/article/details/48783923) - [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/) +- [MySQL locking for the busy web developer](https://www.brightbox.com/blog/2013/10/31/on-mysql-locks/) +- [浅入浅出 MySQL 和 InnoDB](https://draveness.me/mysql-innodb)