【MySQL数据库】谈谈事务的隔离级别有什么?

分析了一些面试题,发现关于事务的隔离级别问的也很频繁,于是就特地来学习这一块的知识,并进行总结整理自己的思路,希望会对有需要的人有一些帮助。

一、所谓事务

事务简单的来说就是数据库的一组操作要么一起成功要么一起失败。
事务具有以下四个属性:原子性、一致性、隔离性、持久性,通常称为ACID特性

  • 原子性(atomicity):一个事务是不可分割的工作单位,一个事务中的工作要么都做,要么都不做。
  • 一致性(consistency):事务必须是使得数据库从一个一致性状态变到另一个一致性状态,一致性与原子性密不可分。
  • 隔离性(isolation)。一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
  • 持久性(durability)。持久性也称永久性(permanence),指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。

今天我们主要来探讨的是事务的隔离性中的隔离级别。

二、隔离性与隔离级别

为什么会有隔离级别的出现呢?原因是当数据库中多个事务同时执行时,可能出现脏读(dirty read),不可重复读(non - repeatable read),幻读(phantom read)等问题,于是就出现了隔离级别。

  • 脏读:A事务读取B事务尚未提交的数据,此时如果B事务发生错误并执行回滚操作,那么A事务读取到的数据就是脏数据
  • 不可重复读:一个事务较大,执行时间较长,执行期间前后读取同一个数据得到的结果不同,就称为不可重复读。
  • 幻读:事务A在执行读取操作,需要两次统计数据的总量,而两次统计出的数据总量不一致,称为幻读。

注意:不可重复读是指多次读取同一个数据的内容不一致,而幻读是指多次读取数据总量不一致,对于不重复读,只需要锁某一行数据,对于幻读则需要锁整个表。

了解了出现隔离级别的原因后,再来了解一下隔离级别有哪些:

  • 读未提交(read uncommitted):一个事务还没有提交,他做的更改就可以被其它事务看到。
  • 读提交(read committed):一个事务提交以后,他做的更改才可以被其它事务看到。
  • 可重复读(repeatable read):一个事务再执行过程中看到的数据,总和这个事务在启动时看到的数据一致。
  • 串行化(serializable):对于同一行记录,读会加“读锁”,写会加“写锁”当发生冲突时,后一个事务必须等前一个事务完执行成后才能继续执行。

这四种隔离级别,是否存在脏读、不可重复读、幻读的情况:

隔离级别 脏读 不可重复读 幻读
读未提交
读提交
可重复读
串行化

当然隔离级别越高,效率就越低,所以应该找到一个平衡点。
接下来,我们使用一个实例,来进一步了解这四个隔离级别。
其中,事务A为多次读取数据,事务B为将V的值由1修改为2,下面是按照时间顺序得执行过程。其中(V1,V2,V3分别代表在不同时间读取V得值)

事务A 事务B
启动事务,读取数据V =1 启动事务
读取数据V= 1
将V的值修改为 2
读取数据V1
提交事务B
读取到值V2
提交事务A
读取到值V3

那么使用不同得隔离级别,不同时刻得到得值就不相同:

隔离级别 V1值 V2值 V3值
读未提交 2 2 2
读提交 1 2 2
可重复读 1 1 2
串行化 1 1 2

其中读未提交,表示只要B修改后A立马就可以读到修改后得数值;
读提交是等到B事务提交后,A才可以读到B得修改内容;
而可重复读中,事务A开始读到得V值是1那么直到事务A执行结束前,读到的都是起始时的值1;
对于串行化,由于A事务首先读到V的值,当B事务准备修改V的值时,就会被锁定,直到事务A提交后,才能继续执行B中的操作。

在MySQL中的默认隔离级别是:可重复读, 而在SQL Sever 和Oracle 中默认隔离级别是:读提交

这里为什么MySQL不使用读提交呢?原因是在MySQL5.0版本前,binlog只支持STATEMENT这种复制格式,而这种格式在读已提交(Read Commited)这个隔离级别下主从复制是有bug的,因此Mysql将可重复读(Repeatable Read)作为默认的隔离级别。

三、避免使用长事务

我们了解了事务隔离的各种级别后,那么事务隔离具体是怎样实现的呢?
在MySQL中,实际上每条记录在更新的时候都会同时记录一条回滚操作。记录上的最新值通过回滚操作都可以得到未修改前的值,不同时刻启动的事务会有不同的read-view来表示某个操作执行前的状态。
而长事务意味着系统里面会存在很老的事务视图。由于这些事务随时可能访问数据库里面的任何数据,所以这个事务提交之前,数据库里面它可能用到的回滚记录都必须保留,这就会导致大量占用存储空间。

以上就是自己对事务的隔离级别的理解,有任何问题欢迎指正。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章