0%

数据管理与分析 - 事务的隔离级别

数据库遵循的是两段锁协议,将事务分成两个阶段,加锁阶段和解锁阶段(所以叫两段锁)

  • 加锁阶段:在该阶段可以进行加锁操作。在对任何数据进行读操作之前要申请并获得S锁(共享锁,其它事务可以继续加共享锁,但不能加排它锁),在进行写操作之前要申请并获得X锁(排它锁,其它事务不能再获得任何锁)。加锁不成功,则事务进入等待状态,直到加锁成功才继续执行。
  • 解锁阶段:当事务释放了一个封锁以后,事务进入解锁阶段,在该阶段只能进行解锁操作不能再进行加锁操作。

事务的异常等级

事务的隔离级别是指:多个读写操作达到一定的隔离性要求。最高隔离级别是冲突可串行化

串行化就是把同一个事务要做的读写操作按先后顺序排到一块。并发事务可以调整成串行化的话,就称为冲突可串行化。


例. 先导解释:r1(A),其中r代read表读操作,1代表事务1,A代表A类数据。w2(B),w代表write写操作,2代表事务2,B代表数据B。

r1(A)w1(A)r2(A)w2(A)r1(B)w1(B)r2(B)w2(B) 总共8个操作,2个事务并发执行。

在操作不冲突的情况下,变换可得:

r1(A)w1(A)r1(B)w1(B)r2(A)w2(A)r2(B)w2(B)

这就相当于执行了串行操作T1事务,T2事务。于是,这就是冲突可串行化。


如果不满足冲突可串行化,则会产生以下异常:

脏写

T1在T2提交前修改同一数据

脏读

T1在T2提交前读取T1修改的数据

T1 T2
开始事务
开始事务
查询账户余额为2000
取款1000,余额1000
查询账余额为1000(产生脏读)
取款异常,事务回滚,余额变更为2000
收入2000,余额为3000
提交事务
备注:按正确逻辑,应为4000

不可重复读

T1在T2修改并提交前读取了同一数据项,且有可能再次读取同一数据项

T1 T2
开始事务
开始事务
查询账户余额为2000
其他操作…
取款1000,余额1000
提交事务
第二次查询余额为1000(不可重复读)
备注:按正确逻辑,事务T1两次数据应该一致

幻读

Transaction T1 reads a set of data items satisfying some. Transaction T2 then creates data items that satisfy T1s and commits. If T1 then repeats its read with the same , it gets a set of data items different from the first read.

T1 T2
select * where dept =”Acct”
//find(“sue”,”Acct”) and (“Tim”,”Acct”)
insert (“Joe”,”Acct”) and commit
select * where dept =”Acct”
//find(“sue”,”Acct”) and (“Tim”,”Acct”) and
//(“Joe”,”Acct”)

事物的隔离级别

防止产生不同等级的异常 对应 不同的隔离级别,但是都必须满足不产生脏写

隔离级别 脏读 不可重复读 幻读
read un-committed 可能产生 可能产生 可能产生
read committed / 可能产生 可能产生
repeatable read / / 可能产生
serializable / / /

隔离级别越高,提供的隔离性保障越强,并发能力也就越弱,实现代价很大,所以很多关系型数据库仅能做到RC级别,MySQL的默认隔离级别就是RC。

分布式系统的并发控制与一致性协议

并发控制

Ø 保证并发事务的多个操作之间不相互影响(事务的写入对并发事务的可见性)

Ø 对 并发事务间相互影响 的约束

Ø 以 隔离级别 作为衡量标准

一致性协议

Ø 保持多个副本数据的一致,即要求多副本上事务执行顺序是 一致的(事务的写入以何种顺序可见)

Ø 对 事务顺序 的约束

Ø 以 一致性级别 作为衡量标准


一个仅保证可串行化的系统在多副本环境下是正确的吗?

Ø 可串行化系统只保证一个串行的顺序,而对于具体的顺序并未加以限制

Ø 而分布式场景下,缺乏一个同步时钟,因此不同节点上操作顺序发生时 间错乱,该现象称为“time travel

Ø time travel主要由主从数据库异步复制引起。

总结:没有任何一致性保证的隔离保证并不是特别有用,分布式系统中需要 两者结合共同保证数据库状态的正确性

image-20220423215407034


更多实践内容参考 https://tech.meituan.com/2014/08/20/innodb-lock.html