auto commit

This commit is contained in:
CyC2018 2018-03-18 14:37:44 +08:00
parent f8e006f604
commit c38db6259b
2 changed files with 23 additions and 33 deletions

View File

@ -9,7 +9,6 @@
* [封锁类型](#封锁类型)
* [封锁粒度](#封锁粒度)
* [封锁协议](#封锁协议)
* [乐观锁和悲观锁](#乐观锁和悲观锁)
* [四、隔离级别](#四隔离级别)
* [五、数据库系统概述](#五数据库系统概述)
* [基本术语](#基本术语)
@ -87,6 +86,8 @@ T<sub>1</sub> 读取某个范围的数据T<sub>2</sub> 在这个范围内插
产生并发不一致性问题主要原因是破坏了事务的隔离性,解决方法是通过并发控制来保证隔离性。
在没有并发的情况下,事务以串行的方式执行,互不干扰,因此可以保证隔离性。在并发的情况下,如果能通过并发控制,让事务的执行结果和某一个串行执行的结果相同,就认为事务的执行结果满足隔离性要求,也就是说是正确的。把这种事务执行方式成为 **可串行化调度**
并发控制可以通过封锁来实现,但是封锁操作都要用户自己控制,相当复杂。数据库管理系统提供了事务的隔离级别,让用户以一种更轻松的方式处理并发一致性问题。
# 三、封锁
@ -106,7 +107,6 @@ T<sub>1</sub> 读取某个范围的数据T<sub>2</sub> 在这个范围内插
<div align="center"> <img src="../pics//1a851e90-0d5c-4d4f-ac54-34c20ecfb903.jpg" width="300"/> </div><br>
应该尽量只锁定需要修改的那部分数据,而不是所有的资源。锁定的数据量越少,发生锁争用的可能就越小,系统的并发程度就越高。
但是加锁需要消耗资源,锁的各种操作,包括获取锁,检查锁是否已经解除、释放锁,都会增加系统开销。因此封锁粒度越小,系统开销就越大。需要在锁开销以及数据安全性之间做一个权衡。
@ -117,8 +117,6 @@ MySQL 中提供了两种封锁粒度:行级锁以及表级锁。
### 1. 三级封锁协议
<div align="center"> <img src="../pics//785806ed-c46b-4dca-b756-cebe7bf8ac3a.jpg"/> </div><br>
<font size=4> **1.1 一级封锁协议** </font> </br>
事务 T 要修改数据 A 时必须加 X 锁,直到事务结束才释放锁。
@ -137,58 +135,50 @@ MySQL 中提供了两种封锁粒度:行级锁以及表级锁。
可以解决不可重复读的问题,因为读 A 时,其它事务不能对 A 加 X 锁,从而避免了在读的期间数据发生改变。
<div align="center"> <img src="../pics//20368ec9-972e-4d6a-8050-3948334bcda0.jpg" width="800"/> </div><br>
### 2. 两段锁协议
加锁和解锁分为两个阶段进行。
加锁和解锁分为两个阶段进行,事务 T 对数据 A 进行或者写操作之前,必须先获得对 A 的封锁并且在释放一个封锁之前T 不能再获得任何的其它锁。
事务遵循两段锁协议是保证并发操作可串行化调度的充分条件。例如以下操作满足两段锁协议,它是可串行化调度。
```html
lock-x(A)...lock-s(B)...lock-s(c)...unlock(A)...unlock(C)...unlock(B)
```
## 乐观锁和悲观锁
但不是必要条件,例如以下操作不满足两段锁协议,但是它还是可串行化调度。
### 1. 悲观锁
假定会发生并发冲突,屏蔽一切可能违反数据完整性的操作。
Java synchronized 就属于悲观锁的一种实现,每次线程要修改数据时都先获得锁,保证同一时刻只有一个线程能操作数据,其他线程则会被阻塞。
### 2. 乐观锁
假设不会发生并发冲突,只在提交操作时检查是否违反数据完整性。
Java JUC 中的 Atomic 包就是乐观锁的一种实现AtomicInteger 通过 CASCompare And Set操作实现线程安全的自增操作。
乐观锁有两种实现方式,数据版本和时间戳。它们都需要在数据库表中增加一个字段,使用这个字段来判断数据是否过期。例如,数据版本实现方式中,需要在数据库表中增加一个数字类型的 version 字段,当读取数据时,将 version 字段的值一同读出。随后数据每更新一次,对此 version 值加 1。当提交更新的时候判断读出的 version 和数据库表中的 version 是否一致,如果一致,则予以更新;否则认为是过期数据。
### 3. MySQL 隐式和显示锁定
MySQL InnoDB 采用的是两阶段锁协议。在事务执行过程中,随时都可以执行锁定,锁只有在执行 COMMIT 或者 ROLLBACK 的时候才会释放并且所有的锁是在同一时刻被释放。前面描述的锁定都是隐式锁定InnoDB 会根据事务隔离级别在需要的时候自动加锁。
另外InnoDB 也支持通过特定的语句进行显示锁定,这些语句不属于 SQL 规范:
- SELECT ... LOCK IN SHARE MODE
- SELECT ... FOR UPDATE
```html
lock-x(A)...unlock(A)...lock-s(B)...unlock(B)...lock-s(c)...unlock(C)...
```
# 四、隔离级别
<font size=4> **1. 未提交读READ UNCOMMITTED** </font> </br>
事务中的修改,即使没有提交,对其它事务也是可见的。事务可以读取未提交的数据,这也被称为脏读。
事务中的修改,即使没有提交,对其它事务也是可见的。事务可以读取未提交的数据,这也被称为脏读。
<font size=4> **2. 提交读READ COMMITTED** </font> </br>
一个事务只能读取已经提交的事务所做的修改。换句话说,一个事务所在的修改在提交之前对其它事务是不可见的。这个级别有时候也叫做不可重复读,因为两次执行同样的查询,可能会得到不一样的结果。
一个事务只能读取已经提交的事务所做的修改。换句话说,一个事务所在的修改在提交之前对其它事务是不可见的。
<font size=4> **3. 可重复读REPEATABLE READ** </font> </br>
解决了脏读的问题,保证在同一个事务中多次读取同样的记录结果是一致的。
但是会出现幻读的问题,所谓幻读,指的是某个事务在读取某个范围内的记录时,另一个事务会在范围内插入数据,当之前的事务再次读取该范围的记录时,会产生幻行。
<font size=4> **4. 可串行化SERIALIXABLE** </font> </br>
强制事务串行执行,避免幻读。
强制事务串行执行。
<font size=4> **5. 总结** </font> </br>
| 隔离级别 | 脏读 | 不可重复读 | 幻影读 |
| --- | --- | --- | --- |
| 未提交读 | YES | YES | YES |
| 提交读 | NO | YES | YES |
| 可重复读 | NO | NO | YES |
| 可串行化 | NO | NO | NO |
# 五、数据库系统概述

Binary file not shown.

After

Width:  |  Height:  |  Size: 105 KiB