Isolation 隔离级别

Isolation level/lock
write lock
read lock
range lock
Read Uncommitted
❌
❌
❌
Read Committed
✅
❌
❌
Repeatable Read
✅
✅
❌
Serializable
✅
✅
✅
Read phenomena(读数据时出现的问题)
用users表进行查询,下面的例子都是两个事务 T1 和 T2,T1执行查询,T2修改数据并提交。
users
id
name
age
1
Joe
20
2
Jill
25
Dirty reads
T1查询 => T2修改 => T1再查询 => T2提交
T1两次查询得到的结果不一样,因为读到了T2未提交的修改,如果T2回滚了,T1第二次读到的结果就是错的。

Non-repeatable reads
T1查询 => T2修改,提交 => T1再查询
T1这个事务里读到的同一行记录不一样。

什么时候出现?
1,加锁控制并发的数据库里,不对SELECT加锁或者SELECT加锁后马上释放了会导致这种情况。
2,MVCC的数据库里,遇到版本冲突时不回滚事务会导致这种情况。
解决方法
1,加锁控制并发的数据库里,对SELECT加锁并且事务结束时再释放。
2,MVCC的数据库里,正常执行,只是T1在整个执行过程中读到的数据都是其开始时的快照,在提交时验证结果是否和串行执行T1 T2等价,不等价则T1回滚。
Phantom reads
和Non-repeatable reads类似,可以算是一种特殊情况。
T1范围查询 => T2 新增或删除行的修改,提交 => T1再范围查询

发生这种情况是因为在执行SELECT ... WHERE进行范围查询是没有获取 range locks ,串行化可以解决这个问题。
PS:lost updates
https://codingsight.com/the-lost-update-problem-in-concurrent-transactions/
Why is it a “lost update” in the Read Committed Transactions example of Oracle documentation?
T1 读id=1的age为20 => T2 读id=1的age为20 => T1修改age=100 where id = 1 => T2修改age=200 where id = 1(要等待T1提交完) => T1提交 => T2提交
最终结果是T2提交的结果,T1执行成功但是其结果丢失了,咋一看即使串行执行也是这个效果,没什么问题,但是如果场景是售卖商品的话就有问题了,如下图,T1卖了2个把剩余个数置为10,T2卖了3个把剩余个数置为9,最终数据库里存的9,错误。
这里的关键是T1 T2最开始读的是同一个数据,但是T1提交完没有通知T2已经改了该数据(也可以说是T2没有意识到T1已经改了),T2以为自己还是在最开始的数据的基础上做的修改。
如何解决呢,还是加读锁,在Repeatable reads的级别可以解决,但是Read committed会出现这个问题。

Isolation levels 隔离级别(解决上面说的问题)
Serializable
1,加锁控制并发的数据库里,读锁 写锁 范围锁(select时加范围锁),并且在事务结束时释放。
2,MVCC的数据库里,遇到版本冲突时回滚事务。
Repeatable reads
加锁控制并发的数据库里,读锁 写锁,并且在事务结束时释放。但不获取范围锁,所以会出现Phantom reads。
Read committed
字面意思,就是读的都是committed的数据。
和Repeatable reads相比,读锁SELECT之后会马上释放,而不是事务结束时释放。所以会出现Phantom reads 和 Non-repeatable reads。
由于有写锁,所以脏读Dirty reads场景里T1第二次读要等待T2结束完才能读,因为被加锁了。(是这样吧?写锁会禁止读吗?)
Read uncommitted
三种问题都会出现。
Last updated
Was this helpful?