diff --git a/docs/notes/数据库系统原理.md b/docs/notes/数据库系统原理.md index 7b84e897..8531af97 100644 --- a/docs/notes/数据库系统原理.md +++ b/docs/notes/数据库系统原理.md @@ -47,7 +47,7 @@ 事务指的是满足 ACID 特性的一组操作,可以通过 Commit 提交一个事务,也可以使用 Rollback 进行回滚。 -

+

## ACID @@ -94,25 +94,25 @@ MySQL 默认采用自动提交模式。也就是说,如果不显式使用`STAR T1 和 T2 两个事务都对一个数据进行修改,T1 先修改,T2 随后修改,T2 的修改覆盖了 T1 的修改。 -

+

## 读脏数据 T1 修改一个数据,T2 随后读取这个数据。如果 T1 撤销了这次修改,那么 T2 读取的数据是脏数据。 -

+

## 不可重复读 T2 读取一个数据,T1 对该数据做了修改。如果 T2 再次读取这个数据,此时读取的结果和第一次读取的结果不同。 -

+

## 幻影读 T1 读取某个范围的数据,T2 在这个范围内插入新的数据,T1 再次读取这个范围的数据,此时读取的结果和和第一次读取的结果不同。 -

+

---- @@ -162,17 +162,12 @@ MySQL 中提供了两种封锁粒度:行级锁以及表级锁。 各种锁的兼容关系如下: -| - | X | IX | S | IS | -| :--: | :--: | :--: | :--: | :--: | -| **X** |× |× |× | ×| -| **IX** |× |√ |× | √| -| **S** |× |× |√ | √| -| **IS** |× |√ |√ | √| +

解释如下: -- 任意 IS/IX 锁之间都是兼容的,因为它们只是表示想要对表加锁,而不是真正加锁; -- 这里的 X/IX/S/IS 锁都是表级锁,IX 锁和行级的 X 锁兼容,两个事务可以对两个数据行加 X 锁。(事务 T1 想要对数据行 R1 加 X 锁,事务 T2 想要对同一个表的数据行 R2 加 X 锁,两个事务都需要对该表加 IX 锁,但是 IX 锁是兼容的,并且 IX 锁与行级的 X 锁也是兼容的,因此两个事务都能加锁成功,对同一个表中的两个数据行做修改。) +- 任意 IS/IX 锁之间都是兼容的,因为它们只表示想要对表加锁,而不是真正加锁; +- 这里兼容关系针对的是表级锁,而表级的 IX 锁和行级的 X 锁兼容,两个事务可以对两个数据行加 X 锁。(事务 T1 想要对数据行 R1 加 X 锁,事务 T2 想要对同一个表的数据行 R2 加 X 锁,两个事务都需要对该表加 IX 锁,但是 IX 锁是兼容的,并且 IX 锁与行级的 X 锁也是兼容的,因此两个事务都能加锁成功,对同一个表中的两个数据行做修改。) ## 封锁协议 @@ -184,20 +179,7 @@ MySQL 中提供了两种封锁粒度:行级锁以及表级锁。 可以解决丢失修改问题,因为不能同时有两个事务对同一个数据进行修改,那么事务的修改就不会被覆盖。 -| T1 | T2 | -| :--: | :--: | -| lock-x(A) | | -| read A=20 | | -| | lock-x(A) | -| | wait | -| write A=19 |. | -| commit |. | -| unlock-x(A) |. | -| | obtain | -| | read A=19 | -| | write A=21 | -| | commit | -| | unlock-x(A)| +

**二级封锁协议** @@ -205,20 +187,8 @@ MySQL 中提供了两种封锁粒度:行级锁以及表级锁。 可以解决读脏数据问题,因为如果一个事务在对数据 A 进行修改,根据 1 级封锁协议,会加 X 锁,那么就不能再加 S 锁了,也就是不会读入数据。 -| T1 | T2 | -| :--: | :--: | -| lock-x(A) | | -| read A=20 | | -| write A=19 | | -| | lock-s(A) | -| | wait | -| rollback | .| -| A=20 |. | -| unlock-x(A) |. | -| | obtain | -| | read A=20 | -| | unlock-s(A)| -| | commit | +

+ **三级封锁协议** @@ -226,26 +196,13 @@ MySQL 中提供了两种封锁粒度:行级锁以及表级锁。 可以解决不可重复读的问题,因为读 A 时,其它事务不能对 A 加 X 锁,从而避免了在读的期间数据发生改变。 -| T1 | T2 | -| :--: | :--: | -| lock-s(A) | | -| read A=20 | | -| |lock-x(A) | -| | wait | -| read A=20| . | -| commit | .| -| unlock-s(A) |. | -| | obtain | -| | read A=20 | -| | write A=19| -| | commit | -| | unlock-X(A)| +

### 2. 两段锁协议 加锁和解锁分为两个阶段进行。 -可串行化调度是指,通过并发控制,使得并发执行的事务结果与某个串行执行的事务结果相同。 +可串行化调度是指,通过并发控制,使得并发执行的事务结果与某个串行执行的事务结果相同。串行执行的事务互不干扰,不会出现并发一致性问题。 事务遵循两段锁协议是保证可串行化调度的充分条件。例如以下操作满足两段锁协议,它是可串行化调度。 @@ -253,7 +210,7 @@ MySQL 中提供了两种封锁粒度:行级锁以及表级锁。 lock-x(A)...lock-s(B)...lock-s(C)...unlock(A)...unlock(C)...unlock(B) ``` -但不是必要条件,例如以下操作不满足两段锁协议,但是它还是可串行化调度。 +但不是必要条件,例如以下操作不满足两段锁协议,但它还是可串行化调度。 ```html lock-x(A)...unlock(A)...lock-s(B)...unlock(B)...lock-s(C)...unlock(C) diff --git a/notes/pics/image-20191207214442687.png b/notes/pics/image-20191207214442687.png new file mode 100644 index 00000000..d4babb56 Binary files /dev/null and b/notes/pics/image-20191207214442687.png differ diff --git a/notes/pics/image-20191207220440451.png b/notes/pics/image-20191207220440451.png new file mode 100644 index 00000000..fbb4854e Binary files /dev/null and b/notes/pics/image-20191207220440451.png differ diff --git a/notes/pics/image-20191207220831843.png b/notes/pics/image-20191207220831843.png new file mode 100644 index 00000000..0d172aeb Binary files /dev/null and b/notes/pics/image-20191207220831843.png differ diff --git a/notes/pics/image-20191207221128997.png b/notes/pics/image-20191207221128997.png new file mode 100644 index 00000000..c3b256ca Binary files /dev/null and b/notes/pics/image-20191207221128997.png differ diff --git a/notes/pics/image-20191207221313819.png b/notes/pics/image-20191207221313819.png new file mode 100644 index 00000000..38fd7d69 Binary files /dev/null and b/notes/pics/image-20191207221313819.png differ diff --git a/notes/pics/image-20191207221744244.png b/notes/pics/image-20191207221744244.png new file mode 100644 index 00000000..32c0ded2 Binary files /dev/null and b/notes/pics/image-20191207221744244.png differ diff --git a/notes/pics/image-20191207221920368.png b/notes/pics/image-20191207221920368.png new file mode 100644 index 00000000..c1df6edb Binary files /dev/null and b/notes/pics/image-20191207221920368.png differ diff --git a/notes/pics/image-20191207222102010.png b/notes/pics/image-20191207222102010.png new file mode 100644 index 00000000..a0d37b69 Binary files /dev/null and b/notes/pics/image-20191207222102010.png differ diff --git a/notes/pics/image-20191207222134306.png b/notes/pics/image-20191207222134306.png new file mode 100644 index 00000000..3a30fe59 Binary files /dev/null and b/notes/pics/image-20191207222134306.png differ diff --git a/notes/pics/image-20191207222237925.png b/notes/pics/image-20191207222237925.png new file mode 100644 index 00000000..4199f624 Binary files /dev/null and b/notes/pics/image-20191207222237925.png differ diff --git a/notes/数据库系统原理.md b/notes/数据库系统原理.md index 7b84e897..8531af97 100644 --- a/notes/数据库系统原理.md +++ b/notes/数据库系统原理.md @@ -47,7 +47,7 @@ 事务指的是满足 ACID 特性的一组操作,可以通过 Commit 提交一个事务,也可以使用 Rollback 进行回滚。 -

+

## ACID @@ -94,25 +94,25 @@ MySQL 默认采用自动提交模式。也就是说,如果不显式使用`STAR T1 和 T2 两个事务都对一个数据进行修改,T1 先修改,T2 随后修改,T2 的修改覆盖了 T1 的修改。 -

+

## 读脏数据 T1 修改一个数据,T2 随后读取这个数据。如果 T1 撤销了这次修改,那么 T2 读取的数据是脏数据。 -

+

## 不可重复读 T2 读取一个数据,T1 对该数据做了修改。如果 T2 再次读取这个数据,此时读取的结果和第一次读取的结果不同。 -

+

## 幻影读 T1 读取某个范围的数据,T2 在这个范围内插入新的数据,T1 再次读取这个范围的数据,此时读取的结果和和第一次读取的结果不同。 -

+

---- @@ -162,17 +162,12 @@ MySQL 中提供了两种封锁粒度:行级锁以及表级锁。 各种锁的兼容关系如下: -| - | X | IX | S | IS | -| :--: | :--: | :--: | :--: | :--: | -| **X** |× |× |× | ×| -| **IX** |× |√ |× | √| -| **S** |× |× |√ | √| -| **IS** |× |√ |√ | √| +

解释如下: -- 任意 IS/IX 锁之间都是兼容的,因为它们只是表示想要对表加锁,而不是真正加锁; -- 这里的 X/IX/S/IS 锁都是表级锁,IX 锁和行级的 X 锁兼容,两个事务可以对两个数据行加 X 锁。(事务 T1 想要对数据行 R1 加 X 锁,事务 T2 想要对同一个表的数据行 R2 加 X 锁,两个事务都需要对该表加 IX 锁,但是 IX 锁是兼容的,并且 IX 锁与行级的 X 锁也是兼容的,因此两个事务都能加锁成功,对同一个表中的两个数据行做修改。) +- 任意 IS/IX 锁之间都是兼容的,因为它们只表示想要对表加锁,而不是真正加锁; +- 这里兼容关系针对的是表级锁,而表级的 IX 锁和行级的 X 锁兼容,两个事务可以对两个数据行加 X 锁。(事务 T1 想要对数据行 R1 加 X 锁,事务 T2 想要对同一个表的数据行 R2 加 X 锁,两个事务都需要对该表加 IX 锁,但是 IX 锁是兼容的,并且 IX 锁与行级的 X 锁也是兼容的,因此两个事务都能加锁成功,对同一个表中的两个数据行做修改。) ## 封锁协议 @@ -184,20 +179,7 @@ MySQL 中提供了两种封锁粒度:行级锁以及表级锁。 可以解决丢失修改问题,因为不能同时有两个事务对同一个数据进行修改,那么事务的修改就不会被覆盖。 -| T1 | T2 | -| :--: | :--: | -| lock-x(A) | | -| read A=20 | | -| | lock-x(A) | -| | wait | -| write A=19 |. | -| commit |. | -| unlock-x(A) |. | -| | obtain | -| | read A=19 | -| | write A=21 | -| | commit | -| | unlock-x(A)| +

**二级封锁协议** @@ -205,20 +187,8 @@ MySQL 中提供了两种封锁粒度:行级锁以及表级锁。 可以解决读脏数据问题,因为如果一个事务在对数据 A 进行修改,根据 1 级封锁协议,会加 X 锁,那么就不能再加 S 锁了,也就是不会读入数据。 -| T1 | T2 | -| :--: | :--: | -| lock-x(A) | | -| read A=20 | | -| write A=19 | | -| | lock-s(A) | -| | wait | -| rollback | .| -| A=20 |. | -| unlock-x(A) |. | -| | obtain | -| | read A=20 | -| | unlock-s(A)| -| | commit | +

+ **三级封锁协议** @@ -226,26 +196,13 @@ MySQL 中提供了两种封锁粒度:行级锁以及表级锁。 可以解决不可重复读的问题,因为读 A 时,其它事务不能对 A 加 X 锁,从而避免了在读的期间数据发生改变。 -| T1 | T2 | -| :--: | :--: | -| lock-s(A) | | -| read A=20 | | -| |lock-x(A) | -| | wait | -| read A=20| . | -| commit | .| -| unlock-s(A) |. | -| | obtain | -| | read A=20 | -| | write A=19| -| | commit | -| | unlock-X(A)| +

### 2. 两段锁协议 加锁和解锁分为两个阶段进行。 -可串行化调度是指,通过并发控制,使得并发执行的事务结果与某个串行执行的事务结果相同。 +可串行化调度是指,通过并发控制,使得并发执行的事务结果与某个串行执行的事务结果相同。串行执行的事务互不干扰,不会出现并发一致性问题。 事务遵循两段锁协议是保证可串行化调度的充分条件。例如以下操作满足两段锁协议,它是可串行化调度。 @@ -253,7 +210,7 @@ MySQL 中提供了两种封锁粒度:行级锁以及表级锁。 lock-x(A)...lock-s(B)...lock-s(C)...unlock(A)...unlock(C)...unlock(B) ``` -但不是必要条件,例如以下操作不满足两段锁协议,但是它还是可串行化调度。 +但不是必要条件,例如以下操作不满足两段锁协议,但它还是可串行化调度。 ```html lock-x(A)...unlock(A)...lock-s(B)...unlock(B)...lock-s(C)...unlock(C)