细品mysql的事务隔离机制

背景

既然聊的是Mysql事务的隔离机制,那在这里我们就默认mysql使用的是InnoDB引擎。事务这个词也还算抽象,在这里我就把大家当做大黄鸭,都细细的聊一边。

为什么MYSQL数据库需要事务
  • 在回答这个问题之前,先分析一下问题,数据库:也可以称为数据管理系统,存储数据的一个系统,将我们所需要的数据进行持久化存储,再着就是事务:这本就是一个抽象的概念,我在这里把他描述为一个过程,一个事件的成功,必然会经过一个过程,这个过程中有可能失败,当他失败的时候就会回到最初的状态。
  • 对于事务,我们结合真实场景的列子,当我们在进行转一笔钱时,刚开始我们余额是500元,我们开一个会员。我们将开会员认为是一个事务,最终成功的状态只有一个,就是我们可以在平台上看会员专属片了,且我们的余额会被扣减。

面试mysql隔离机制 mysql隔离机制及实现原理_隔离级别

  • 如上图这个流程认为是一个事务,但是对于系统来说,如何将这个事务抽象下来呢?让你可以看片成为专属会员,对于系统的来说只是在数据库存储你这个用户的信息的某个字段发生了改变
  • 你品,你细品,将这个事务进行拆分为很小的块,那这个块也得符合大局的规则,也就是符合事务的特性规则(ACID)。这个块就是将用户的是否是会员字段的值进行更新为是且持久化。这个步骤是谁来做呢? 那就是我们的数据库管理系统了(DBMS)MYSQL了。但是这个过程得保证为一个事务,在这个值被修改的过程中中途失败的话,仍然还是原来的状态,包括在修改的途中,我不能让其他的事务读取到的是我没有最终落盘的数据。
  • 就是为了达到一个“要么完全成功,要么失败且能回滚到最初状态”这么一个事件,mysql是在在这个过程中的一个步骤 。所以他也得支持这种事件,所以他就有了事务,但是有了事务,事务之前又产生了几个问题。于是又有了事务的几种隔离机制。
理解mysql的事务隔离机制

mysql 事务的几个概念:

  1. 隔离性与隔离级别
  • 什么是隔离性,事务的ACID(Atomicity、Consistency、Isolation、Durability,即原子性、一致性、隔离性、持久性),其中的隔离性我们来细细的品一下。
  • 为什么事务要有隔离性 ,当我们有多个事务的出现的时候,就会出现 脏读,不可重复读,幻读的问题,为了解决这几个问题于是隔离级别就站出来了。
  1. 脏读: 当有一个事务读取到一个事务未提交的数据

面试mysql隔离机制 mysql隔离机制及实现原理_数据_02

  1. 幻读:一个事务读取2次,得到的记录条数不一致。

上图很明显的表示了这个情况,由于在会话 1 之间插入了一个新的值,所以得到的两次数据就不一样了。

  1. 不可重复读:一个事务读取同一条记录2次,得到的结果不一致

这也就是我们 在一个事务中和数据库创建了多次会话,有update 和 select 语句。比如说先进行更新,然后又进行读取。读取的数据是

已经提交的数据,不是他第一次读取到的数据。产生不一致的情况。

上面也描述了,为了解决这些问题,隔离别站出来了,那我们再细细品一下隔离级别。

四种隔离级别
  • 读未提交是指,一个事务还没提交时,它做的变更就能被别的事务看到。可以回想一下,一个问题也没有解决。
  • 读提交是指,一个事务提交之后,它做的变更才会被其他事务看到。提交后才能被看到 ,那这就解决了脏读的问题吗,也就是说我这个事务 没有完成前。其他事物读取到的都是修改事务之前的数据
  • 可重复读是指,一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的。继续结合上面的问题,和启动的数据是一致的,那不可重复读的问题也就解决了不可重复读就是同一个事务中两次读到的数据是不一致的。也可以结合名字记住一 下,隔离级别 可重复读就时解决了不可重复读。当然脏读也解决了,因为事务内读取到的都是刚开始的,更不用说不同事物之间也肯定是读取不到的。
  • 串行化,顾名思义是对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。加锁了,那就没有并发安全问题,应为不会出现竞太条件了。所以都不会出现了。

面试mysql隔离机制 mysql隔离机制及实现原理_回滚_03

MYSQL 的事务机制是如何实现的
  • 在 MySQL 中,实际上每条记录在更新的时候都会同时记录一条回滚操作。记录上的最新值,通过回滚操作,都可以得到前一个状态的值。

面试mysql隔离机制 mysql隔离机制及实现原理_数据_04

  • 假设一个值从 1 被按顺序改成了 2、3、4,在回滚日志里面就会有类似下面的记录。当前值是 4,但是在查询这条记录的时候,不同时刻启动的事务会有不同的 read-view。如图中看到的,在视图 A、B、C 里面,这一个记录的值分别是 1、2、4,同一条记录在系统中可以存在多个版本,就是数据库的多版本并发控制(MVCC)。对于 read-view A,要得到 1,就必须将当前值依次执行图中所有的回滚操作得到。
  • 然后我们在使用时候,不同的隔离级别会选用不同的版本号,如果是可重复读,那读取的版本号是view A ,因为他是初始的版本号。
在使用事务的时候我们应该注意哪些点
  • 在写复杂的事务控制的时候,一定要看下你的MySQL的事务隔离级别,每个公司之间有可能 不一样。
  • 还有就是我们经常说的,少用长事务。如我们 上面所描述
  1. 长事务会产生大量的回滚日志,长事务意味着系统里面会存在很老的事务视图。
  • 由于这些事务随时可能访问数据库里面的任何数据,所以这个事务提交之前,数据库里面它可能用到的回滚记录都必须保留,这就会导致大量占用存储空间。
  • 在 MySQL 5.5 及以前的版本,回滚日志是跟数据字典一起放在 ibdata 文件里的,即使长事务最终提交,回滚段被清理,文件也不会变小。我见过数据只有 20GB,而回滚段有 200GB 的库。最终只好为了清理回滚段,重建整个库。
  1. 会占用锁资源(甚至产生 死锁)就简单思考一下,当有两个长事务时,并发获取的概率就很大。然后就会产生互相等待,产生死锁。