事务[自问自答]

事务隔离性

  • 事务为何需要隔离?
  • 那隔离方式有哪些?
  • 如何实现隔离?
  • 数据库默认的隔离级别?
  • 事务回滚?
  • 回滚日志会一直存在吗


事务为何需要隔离?

很多人都知道事务是具有ACID特性(Atomicity原子性、Consistency一致性、Isolation隔离性,Durability持久性)。那为了做到上面四点,我们就需要对我们稍作一些“手段”,保证事务即使在并发的条件下,也不会出现脏读(dirty read)、不可重复读repeatable read)、幻读(phantom read)的问题,在此前提下,我们所谓的手段就是以隔离的方式来保证事务被我们正确执行。

那隔离方式有哪些?

  1. 读未提交

一个事务还没提交时,它做的变更就能被别的事务看到。如下例子:事务B还未提交,事务A已经能查询到M为2了。
事务[自问自答]_第1张图片

  1. 读提交
    一个事务提交之后,它做的变更才会被其他事务看到,借上面的图说一下,因为事务B未提交,所以事务A查询M后,此时就不是2了,还是1,只有事务B提交后,A再查询时才是2。

  2. 可重复读
    一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。在这个级别下的隔离,在整个事务A的过程中,无论你怎么读取M,它始终待你如初,和事务B、其他事务都无瓜。反过来,在可重复读隔离级别下,只要它未提交变更,它做的事情对其他事务也是不可见的。

  3. 串行化
    对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。

如何实现隔离?

在不同隔离级别的访问中,在数据库里面会创建一个视图,我们的访问的以视图的逻辑结果为准。

  1. “可重复读”隔离级别下,视图在事务启动时创建的,整个事务存在期间都用这个视图。

  2. 在“读提交”隔离级别下,这个视图是在每个 SQL 语句开始执行的时候创建的(事务提交后才执行SQL语句)。

  3. “读未提交”隔离级别下直接返回记录上的最新值,没有视图概念;

  4. “串行化”隔离级别下直接用加锁的方式来避免并行访问

数据库默认的隔离级别?

不同数据库默认的隔离方式可能有所不同,以Oracle 数据库为例子,它的默认隔离级别其实就是“读提交”,而MySQL是“可重复读”
事务[自问自答]_第2张图片
这里就要注意一下,对于一些从 Oracle 迁移到 MySQL 的应用,为保证数据库隔离级别的一致,一定要记得将 MySQL 的隔离级别设置为“读提交”。

事务回滚?

说到回滚,其实隔离的底层实现也和它有着关系。其实在 MySQL 中,每条记录在更新的时候都会同时记录一条回滚操作。记录上的最新值,通过回滚操作,都可以得到前一个状态的值。如下图例子:M一开始是2,然后变为3,此时回滚日志中会写3——>2,然后3变成4,此时回滚日志变成4——>3,不同时刻启动的事务看到的视图read-view不一样(除了读未提交,它没有“视图”这个概念)。
事务[自问自答]_第3张图片像这种同一条记录在系统中可以存在多个版本,也是数据库的多版本并发控制,还有个好听的名字MVCC(乐观锁的实现方式,如何实现?)

回滚日志会一直存在吗

这个肯定不会,如果一直存在,那存储空间岂不是很容易就被爆了。回滚日志会在事务不再需要的时候才删除,即当没有事务再需要用到这些回滚日志时,它就会被out了。那如何判断系统不再需要了呢?即当系统里没有比这个回滚日志有更早的 read-view 的时候。基于此,我们再使用事务时,要注意使用方式,过长的事务会导致过多的回滚日志,而这些日志都是占用存储空间的,存储空间则需要真金白银买的。

你可能感兴趣的:(事务[自问自答],数据库)