数据库隔离级别
文章目录
- 数据库隔离级别
- 问题
- 脏读
- 示意图
- 不可重复读
- 示意图
- 幻读
- 和不可重复读的区别
- 解决思路
- 串行化
- 未提交读
- 简单的比较
- 隔离级别
- 未提交读
- 提交读
- 重复读
- 串行化
- 参考
问题
数据库在设计之初就被要求满足ACID(原子性,一致性,独立性,持久性)四大特性,但是在并发读写的时候,如果不做限制,经常会遇到一些奇奇怪怪的问题
脏读
A事务读取了B事务还没有提交的数据,而这个数据属于B事务在处理过程中产生的脏数据,可能只是临时状态。怎么理解这个临时呢?
- 当B因为后续的异常导致回滚
- B后续的操作中还有对这个数据的修改
那么A读到的这个数据可能就是不一致的。
发生脏读的条件是数据库允许读入还没提交的事务已经修改了的数据。这其实破坏了ACID中的隔离性和一致性
示意图
不可重复读
在一个事务中前后读取数据不一致。
由于事务和事务之间是隔离的,事务应该从一个一致的状态转移到另一个一致的状态,如果在事务处理的过程中还出现了不是由自己触发的中间状态,那么就无法保证最后的数据一致性了。
示意图
幻读
前后多次读取,数据总量不一致。这个
和不可重复读的区别
幻读和不可重复读有什么不一样?
(1) 不可重复读是读取了其他事务更改的数据,针对update操作
解决:使用行级锁,锁定该行,事务A多次读取操作完成后才释放该锁,这个时候才允许其他事务更改刚才的数据。
(2) 幻读是读取了其他事务新增的数据,针对insert和delete操作
解决:使用表级锁,锁定整张表,事务A多次读取数据总量之后才释放该锁,这个时候才允许其他事务新增数据。
解决思路
简单来说,解决的思路就是在数据读写的时候加入一些限制,最常见的就是锁,来保证并发读写的数据安全。
但是,总所周知,锁或者一些控制并发的方式可能会带来性能上的损耗,降低并发数,我们当然不希望看到这样的结果,所以为了平衡数据安全和性能,数据库设计了四个隔离级别,为了满足不同场景下的需求。我们已隔离级别中最极端的两个为例,来解释这样设计的初衷
串行化
简单来说,就是让事务在执行的时候保持和串行执行相同的效果。最简单也最不可能的实现方式就是加锁,A事务执行之前对数据库加个锁,等它执行完再释放,在这期间,其他事务不允许执行。
未提交读
允许出现脏读,基本没什么并发控制。
简单的比较
比较一下上面两种方式,第一种数据非常安全,但是性能很差。而第二种,几乎就没有什么并发控制,性能好,随意跑,但数据也就非常乱了。
隔离级别
这样看下来,我们还需要设计一些中间的隔离级别来平衡一下性能和数据安全。以下就是我们常见的四个数据隔离级别:
未提交读
简单来说就是允许读还未提交的事务所产生的中间数据。也就是公开允许脏读,当然不可重复读和幻读在这种隔离级别下也是不可避免的。
提交读
只允许读其他事务提交之后的数据,这样就避免了脏读。但是如果一个B事务在A事务执行的过程中被触发并修改了数据,那么A事务在B事务执行前后读到的数据就是不一致的,这也就产生了重复度和幻读
重复读
保证在一次事务执行的过程中,前后读取到的数据是一致的。这里的数据指的是数据项,而非一批数据整体,所以如果B事务增加了一列数据,那么A可能前面读到的还是一个记录,后面就变成两个了。
从上面的介绍来看,重复读的隔离级别,能避免脏读和未提交读,但却避免不了幻读。
常见的数据库系统,包括Mysql默认就是重复读的隔离级别
串行化
参考解决思路中对串行化的解释,串行化能够避免上面提到的所有问题,包括:脏读,不可重复读,幻读。是终极解决方案,但成本也巨高