1. ACID
ACID由四个属性的英文单词首字母组成,分别是
1.1 原子性(Atomicity)
一个事务所包含的所有操作,要么全部完成,要么全部不完成,不会在中间某环节结束。即使事务在执行过程中发生错误,也会被回滚(Rollback)到事务开始前的状态,就像这个事务没有执行过一样
1.2 一致性(Consistency)
事务开始之前和事务结束之后,数据库的完整性没有被破坏。事务必须保证数据库可以从一个一致的状态转移到另一个一致的状态,这种一致性要求不仅指常见的数据库完整性约束,有时还需要用户来保证
1.3 隔离性(Isolation)
数据库允许多个并发事务对其数据进行读写和修改,隔离性可以防止多个事务在并发执行时,由于交叉执行而导致的数据出现异常状况。不同的隔离级别有着不同的保证。
1.4 持久性(Durability)
事务结束之后,对数据的修改就是永久的,即便系统出现故障也不会丢失数据
注意: ACID的一致性和CAP定理中的一致性是不一样的,ACID中的一致性属于数据库事务领域的概念,具体含义如上所述;而CAP定理中的C是指线性一致性。虽然单词都一样,但必须清楚的认识到二者是完全不同的“一致性”。
2. 并发事务可能的异常情况
2.1 赃写(Dirty Writer)
指一个事务覆盖了另一个正在运行中、尚未提交的事务写入的值
事务A | 事务B |
---|---|
x=1 | |
x=2 | |
y=2 | |
commit | |
y=1 | |
commit |
2.2 脏读(Dirty Read)
一个事务读到了另一个事务A尚未提交的值(关键问题就在于事务A可能会回滚)。
事务A | 事务B |
---|---|
x=1 | |
Read(x) | |
rollback |
2.3 不可重复读(Non-Repeatable Read)
在一个事务中查询一个值两次,但两次查询的值不同,不可重复读也叫模糊读(Fuzzy Read)。
不可重复读与脏读的区别在于:脏读是由于事务回滚所导致的,而不可重复读是读到了其他事务已经提交的数据
事务A | 事务B |
---|---|
Read(x) | |
x=1 | |
Read(x) | |
commit | commit |
2.4 幻读(Phantim Read)
当一个事务在进行条件查询时,另一个事务在中间插入或删除了匹配该条件的数据,这时再去读,就会发生幻读。
事务A | 事务B |
---|---|
查询用户总数为10 | |
(select cont(*) from user) | |
插入一条新用户数据 | |
(insert into users values (‘MCZ’)) | |
查询用户总数为10 | |
(select cont(*) from user)Read(x) | |
commit | commit |
2.5 更新丢失(Lost Update)
当两个事务读取同一个值,然后都试图将其更新为不同的值时,就会发生更新丢失。
更新丢失的结果就是,两个更新只会有一个更新失效,但执行更新的另一个事务并没有被告知其更新
事务A | 事务B |
---|---|
x=1 | |
x=2 | |
commit | |
commit | |
2.6 读偏斜(Read Skew)
读到了数据一致性约束破话的数据
这里一致性约束通常是指业务逻辑层面上的(注意:这里指ACID层面的一致性)
这里我们假定数据约束是:X+Y=100
事务A | X | Y | 事务B |
---|---|---|---|
50 | 50 | Read(X) | |
X=30 | 30 | 50 | |
Y=70 | 30 | 70 | |
commit | 30 | 70 | Read(Y) |
30 | 70 | commit |
2.7 写偏斜(Write Skew)
两个并发事务都读到了相同的数据集,但随后各自修改了不相干的数据集,导致数据的一致性约束被破坏
这里我们假定数据约束是:X+Y=100
事务A | X | Y | 事务B |
---|---|---|---|
Read(X) | 10 | 20 | Read(X) |
Read(Y) | 10 | 20 | Read(Y) |
x=70 | 70 | 20 | |
commit | 70 | 50 | y=50 |
70 | 50 | commit |
3. 事务的隔离级别
- 串行化(Serializability)
- 可重复读(Repeatable Read)
- 快照隔离(Snapshot Isolation)
- 读已提交(Read Committed)
- 读未提交(Read Uncommitted)
事务的隔离级别根据可用性可以分为两类,矩形中的模型的可用性为不可用(Unavailable),椭圆中的可用性为高可用(Total Available)。
3.1 读未提交(Read Uncommitted)
允许脏读,但不允许更新丢失。
如果一个事务已经开始写数据,则另外一个事务则不允许同时进行写操作,但允许其他事务读此行数据。
该隔离级别可以通过“排他写锁”实现。
3.2 读已提交(Read Committed)
允许不可重复读,但不允许脏读。
读取数据的事务允许其他事务继续访问该行数据,但是未提交的写事务将会禁止其他事务访问该行。
这可以通过“瞬间共享读锁”和“排他写锁”实现。
3.3 快照隔离(Snapshot Isolation)
快照隔离因为每一次读都是从一个过去的快照中读取的,不会出现多次读一个值却读到不一致结果的情况。
因此,能完美的解决不可重复读的问题,但是无法解决 **写偏斜 **或 **幻读。 **
3.4 可重复读(Repeatable Read)
禁止不可重复读和脏读,但是有时可能出现幻读。
读取数据的事务将会禁止写事务(但允许读事务),写事务则禁止任何其他事务。
3.5 串行化(Serializability)
提供严格的事务隔离。它要求事务串行化执行,事务只能一个接着一个地执行,不能并发执行。
仅仅通过“行级锁”是无法实现事务序列化的,必须通过其他机制保证新插入的数据不会被刚执行查询操作的事务访问到。