auto commit

This commit is contained in:
CyC2018 2019-12-08 01:26:22 +08:00
parent 67e70462af
commit b71985e21e
5 changed files with 90 additions and 50 deletions

View File

@ -19,9 +19,10 @@
* [可重复读REPEATABLE READ](#可重复读repeatable-read)
* [可串行化SERIALIZABLE](#可串行化serializable)
* [多版本并发控制](#五多版本并发控制)
* [基本思想](#基本思想)
* [Undo 日志](#undo-日志)
* [版本号](#版本号)
* [隐藏的列](#隐藏的列)
* [Undo 日志](#undo-日志)
* [实现过程](#实现过程)
* [快照读与当前读](#快照读与当前读)
* [Next-Key Locks](#六next-key-locks)
@ -189,7 +190,6 @@ MySQL 中提供了两种封锁粒度:行级锁以及表级锁。
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/image-20191207220831843.png"/> </div><br>
**三级封锁协议**
在二级的基础上要求读取数据 A 时必须加 S 直到事务结束了才能释放 S
@ -249,20 +249,39 @@ SELECT ... FOR UPDATE;
----
| | 脏读 | 不可重复读 | 幻影读 |
| :---: | :---: | :---:| :---: |
| 未提交读 | | | |
| 提交读 | × | | |
| 可重复读 | × | × | |
| 可串行化 | × | × | × |
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/image-20191207223400787.png"/> </div><br>
# 多版本并发控制
多版本并发控制Multi-Version Concurrency Control, MVCC MySQL InnoDB 存储引擎实现隔离级别的一种具体方式用于实现提交读和可重复读这两种隔离级别而未提交读隔离级别总是读取最新的数据行要求很低无需使用 MVCC可串行化隔离级别需要对所有读取的行都加锁单纯使用 MVCC 无法实现
## 版本号
## 基本思想
在封锁一节中提到加锁能解决多个事务同时执行时出现的并发一致性问题但是封锁操作代价很高而多版本并发控制采用无锁机制而是利用版本来解决并发一致性问题它的基本思想是为每个数据行维护创建
在封锁一节中提到加锁能解决多个事务同时执行时出现的并发一致性问题但是加锁操作代价很高并且在实际场景中读多写少所有事务都是只是进行读操作的话就没必要进行加锁
MVCC 的读操作不需要进行加锁并且在可重复读隔离级别下能解决脏读和不可重复读问题它的基本思想是为每个数据行维护多个版本的快照多个事务可以同时去操作这个数据行
事务的修改操作DELETEINSERTUPDATE会去修改该事务对应版本的快照
脏读和不可重复读最根本的原因是事务读取到其它事务未提交的修改在事务在进行读取操作时为了解决脏读和不可重复读问题读取的快照需要满足以下条件快照在该事务开始之后没有被其它事务修改否则会读取到其它事务的未提交的修改操作
## Undo 日志
MVCC 的多版本指的是多个版本的快照这个快照存储在 Undo 日志中该日志通过回滚指针把一个数据行的所有快照连接起来
例如我们在 MySQL 创建一个表 t包含主键 id 和一个字段 x我们先插入一个数据行然后对该数据行执行两次操作
```sql
INSERT INTO t(id, x) VALUES(1, "a");
UPDATE t SET x="b" WHERE id=1;
UPDATE t SET x="c" WHERE id=1;
```
因为我们没有使用 `START TRANSACTION` 将上面的操作当成一个事务来执行根据 MySQL AUTOCOMMIT 机制每个操作都会被当成一个事务来执行所以上面总共涉及到三个事务
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/image-20191208012527591.png"/> </div><br>
## 版本号
- 系统版本号是一个递增的数字每开始一个新的事务系统版本号就会自动递增
- 事务版本号事务开始时的系统版本号
@ -274,17 +293,13 @@ MVCC 在每行记录后面都保存着两个隐藏的列,用来存储两个版
- 创建版本号指示创建一个数据行的快照时的系统版本号
- 删除版本号如果该快照的删除版本未定义或删除版本号大于当前事务版本号表示该快照有效
## Undo 日志
MVCC 使用到的快照存储在 Undo 日志中该日志通过回滚指针把一个数据行Record的所有快照连接起来
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/e41405a8-7c05-4f70-8092-e961e28d3112.jpg" width=""/> </div><br>
## 实现过程
以下实现过程针对可重复读隔离级别
当开始一个事务时该事务的版本号肯定大于当前所有数据行快照的创建版本号理解这一点很关键数据行快照的创建版本号是创建数据行快照时的系统版本号系统版本号随着创建事务而递增因此新创建一个事务时这个事务的系统版本号比之前的系统版本号都大也就是比所有数据行快照的创建版本号都大
当开始一个事务时该事务的版本号肯定大于当前所有数据行快照的创建版本号数据行快照的创建版本号是创建数据行快照时的系统版本号系统版本号随着创建事务而递增因此新创建一个事务时这个事务的系统版本号比之前的系统版本号都大也就是比所有数据行快照的创建版本号都大
### 1. SELECT
@ -308,22 +323,27 @@ MVCC 使用到的快照存储在 Undo 日志中,该日志通过回滚指针把
### 1. 快照读
使用 MVCC 读取的是快照中的数据这样可以减少加锁所带来的开销
MVCC SELECT 操作是快照中的数据不需要进行加锁操作
```sql
select * from table ...;
SELECT * FROM table ...;
```
### 2. 当前读
读取的是最新的数据需要加锁以下第一个语句需要加 S 其它都需要加 X
MVCC 其它会对数据库进行修改的操作INSERTUPDATEDELETE需要加锁操作从而读取最新的数据
```sql
select * from table where ? lock in share mode;
select * from table where ? for update;
insert;
update;
delete;
INSERT;
UPDATE;
DELETE;
```
在进行 SELECT 操作时可以强制指定进行加锁操作以下第一个语句需要加 S 第二个需要加 X
```sql
SELECT * FROM table WHERE ? lock in share mode;
SELECT * FROM table WHERE ? for update;
```
# Next-Key Locks
@ -348,14 +368,14 @@ SELECT c FROM t WHERE c BETWEEN 10 and 20 FOR UPDATE;
## Next-Key Locks
它是 Record Locks Gap Locks 的结合不仅锁定一个记录上的索引也锁定索引之间的间隙是一个前开后闭区间例如一个索引包含以下值10, 11, 13, and 20那么就需要锁定以下区间
它是 Record Locks Gap Locks 的结合不仅锁定一个记录上的索引也锁定索引之间的间隙它锁定一个前开后闭区间例如一个索引包含以下值10, 11, 13, and 20那么就需要锁定以下区间
```sql
(-, 10]
(10, 11]
(11, 13]
(13, 20]
(20, +supremum)
(20, +)
```
# 关系数据库设计理论

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

View File

@ -19,9 +19,10 @@
* [可重复读REPEATABLE READ](#可重复读repeatable-read)
* [可串行化SERIALIZABLE](#可串行化serializable)
* [多版本并发控制](#五多版本并发控制)
* [基本思想](#基本思想)
* [Undo 日志](#undo-日志)
* [版本号](#版本号)
* [隐藏的列](#隐藏的列)
* [Undo 日志](#undo-日志)
* [实现过程](#实现过程)
* [快照读与当前读](#快照读与当前读)
* [Next-Key Locks](#六next-key-locks)
@ -189,7 +190,6 @@ MySQL 中提供了两种封锁粒度:行级锁以及表级锁。
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/image-20191207220831843.png"/> </div><br>
**三级封锁协议**
在二级的基础上要求读取数据 A 时必须加 S 直到事务结束了才能释放 S
@ -249,20 +249,39 @@ SELECT ... FOR UPDATE;
----
| | 脏读 | 不可重复读 | 幻影读 |
| :---: | :---: | :---:| :---: |
| 未提交读 | | | |
| 提交读 | × | | |
| 可重复读 | × | × | |
| 可串行化 | × | × | × |
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/image-20191207223400787.png"/> </div><br>
# 多版本并发控制
多版本并发控制Multi-Version Concurrency Control, MVCC MySQL InnoDB 存储引擎实现隔离级别的一种具体方式用于实现提交读和可重复读这两种隔离级别而未提交读隔离级别总是读取最新的数据行要求很低无需使用 MVCC可串行化隔离级别需要对所有读取的行都加锁单纯使用 MVCC 无法实现
## 版本号
## 基本思想
在封锁一节中提到加锁能解决多个事务同时执行时出现的并发一致性问题但是封锁操作代价很高而多版本并发控制采用无锁机制而是利用版本来解决并发一致性问题它的基本思想是为每个数据行维护创建
在封锁一节中提到加锁能解决多个事务同时执行时出现的并发一致性问题但是加锁操作代价很高并且在实际场景中读多写少所有事务都是只是进行读操作的话就没必要进行加锁
MVCC 的读操作不需要进行加锁并且在可重复读隔离级别下能解决脏读和不可重复读问题它的基本思想是为每个数据行维护多个版本的快照多个事务可以同时去操作这个数据行
事务的修改操作DELETEINSERTUPDATE会去修改该事务对应版本的快照
脏读和不可重复读最根本的原因是事务读取到其它事务未提交的修改在事务在进行读取操作时为了解决脏读和不可重复读问题读取的快照需要满足以下条件快照在该事务开始之后没有被其它事务修改否则会读取到其它事务的未提交的修改操作
## Undo 日志
MVCC 的多版本指的是多个版本的快照这个快照存储在 Undo 日志中该日志通过回滚指针把一个数据行的所有快照连接起来
例如我们在 MySQL 创建一个表 t包含主键 id 和一个字段 x我们先插入一个数据行然后对该数据行执行两次操作
```sql
INSERT INTO t(id, x) VALUES(1, "a");
UPDATE t SET x="b" WHERE id=1;
UPDATE t SET x="c" WHERE id=1;
```
因为我们没有使用 `START TRANSACTION` 将上面的操作当成一个事务来执行根据 MySQL AUTOCOMMIT 机制每个操作都会被当成一个事务来执行所以上面总共涉及到三个事务
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/image-20191208012527591.png"/> </div><br>
## 版本号
- 系统版本号是一个递增的数字每开始一个新的事务系统版本号就会自动递增
- 事务版本号事务开始时的系统版本号
@ -274,17 +293,13 @@ MVCC 在每行记录后面都保存着两个隐藏的列,用来存储两个版
- 创建版本号指示创建一个数据行的快照时的系统版本号
- 删除版本号如果该快照的删除版本未定义或删除版本号大于当前事务版本号表示该快照有效
## Undo 日志
MVCC 使用到的快照存储在 Undo 日志中该日志通过回滚指针把一个数据行Record的所有快照连接起来
<div align="center"> <img src="https://cs-notes-1256109796.cos.ap-guangzhou.myqcloud.com/e41405a8-7c05-4f70-8092-e961e28d3112.jpg" width=""/> </div><br>
## 实现过程
以下实现过程针对可重复读隔离级别
当开始一个事务时该事务的版本号肯定大于当前所有数据行快照的创建版本号理解这一点很关键数据行快照的创建版本号是创建数据行快照时的系统版本号系统版本号随着创建事务而递增因此新创建一个事务时这个事务的系统版本号比之前的系统版本号都大也就是比所有数据行快照的创建版本号都大
当开始一个事务时该事务的版本号肯定大于当前所有数据行快照的创建版本号数据行快照的创建版本号是创建数据行快照时的系统版本号系统版本号随着创建事务而递增因此新创建一个事务时这个事务的系统版本号比之前的系统版本号都大也就是比所有数据行快照的创建版本号都大
### 1. SELECT
@ -308,22 +323,27 @@ MVCC 使用到的快照存储在 Undo 日志中,该日志通过回滚指针把
### 1. 快照读
使用 MVCC 读取的是快照中的数据这样可以减少加锁所带来的开销
MVCC SELECT 操作是快照中的数据不需要进行加锁操作
```sql
select * from table ...;
SELECT * FROM table ...;
```
### 2. 当前读
读取的是最新的数据需要加锁以下第一个语句需要加 S 其它都需要加 X
MVCC 其它会对数据库进行修改的操作INSERTUPDATEDELETE需要加锁操作从而读取最新的数据
```sql
select * from table where ? lock in share mode;
select * from table where ? for update;
insert;
update;
delete;
INSERT;
UPDATE;
DELETE;
```
在进行 SELECT 操作时可以强制指定进行加锁操作以下第一个语句需要加 S 第二个需要加 X
```sql
SELECT * FROM table WHERE ? lock in share mode;
SELECT * FROM table WHERE ? for update;
```
# Next-Key Locks
@ -348,14 +368,14 @@ SELECT c FROM t WHERE c BETWEEN 10 and 20 FOR UPDATE;
## Next-Key Locks
它是 Record Locks Gap Locks 的结合不仅锁定一个记录上的索引也锁定索引之间的间隙是一个前开后闭区间例如一个索引包含以下值10, 11, 13, and 20那么就需要锁定以下区间
它是 Record Locks Gap Locks 的结合不仅锁定一个记录上的索引也锁定索引之间的间隙它锁定一个前开后闭区间例如一个索引包含以下值10, 11, 13, and 20那么就需要锁定以下区间
```sql
(-, 10]
(10, 11]
(11, 13]
(13, 20]
(20, +supremum)
(20, +)
```
# 关系数据库设计理论