mysql事务和隔离级别底层原理浅析

目录
  • 前言
  • 一、事务底层原理浅析
    • 原子性:
    • 持久性
    • 隔离性:
    • 一致性:
  • 二、隔离级别底层原理浅析
  • 三、总结

前言

首先回顾一下什么是事务,事务是数据库操作的最小工作单元,是作为单个逻辑工作单元执行的一系列操作;这些操作作为一个整体一起向系统提交,要么都执行、要么都不执行;事务是一组不可再分割的操作集合(工作逻辑单元)。

事务的特性:

原子性(Atomicity):原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚。一致性(Consistency):事务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。隔离性(Isolation):一个事务的执行不能其它事务干扰。即一个事务内部的操作及使用的数据对其它并发事务是隔离的,并发执行的各个事务之间不能互相干扰。持久性(Durability):指一个事务一旦提交,它对数据库中的数据的改变就应该是永久性的。接下来的其它操作或故障不应该对其执行结果有任何影响。

一、事务底层原理浅析

原子性:

实现原理:undo log

undo log也被成为回滚日志,它是事务实现原子性和隔离性的基础。当事务对数据库进行修改时,InnoDB会生成对应的undo log;如果事务执行失败或调用了rollback,导致事务需要回滚,便可以利用undo log中的信息将数据回滚到修改之前的样子。

undo log属于逻辑日志,它记录的是sql执行相关的信息。当发生回滚时,InnoDB会根据undo log的内容做与之前相反的工作:对于每个insert,回滚时会执行delete;对于每个delete,回滚时会执行insert;对于每个update,回滚时会执行一个相反的update,把数据改回去。

undo 存放在数据库内部的一个特殊段segment中,这个段称为undo段。undo段位于共享表空间中。undo是逻辑日志,因此只是将数据库逻辑的恢复到原来的样子。undo log会产生redo log,也就是undo log的产生会伴随着redo log的产生,因为undo log也需要持久性的保护。

undo log执行记录是在每次写入数据或者修改数据之前。

undo log使用原理:数据库表每行数据会多两列DATA_TRX_ID和DATA_ROLL_PTR(可能还有一列DB_ROW_ID,当没有默认主键时会自动加上这列)。DATA_TRX_ID表示当前数据的事务版本, DATA_ROLL_PTR 则指向刚刚拷贝到

undo log 链中的旧版本记录,undo log是个链表,如果多个事务多次修改会继续生成undo log并通过DATA_ROLL_PTR建立指向关系。用图说明一下:

这样,一旦事务发生回滚,mysql便可以借助undo log实现数据还原,从而保证未提交事务的原子性。

持久性

实现原理:redo log

由于InnoDB作为MySQL的存储引擎,数据是存放在磁盘中的,为了减少磁盘IO,提高读取性能InnoDB提供了缓存池——Buffer Pool。Buffer Pool中包含了磁盘中部分数据页的映射,作为访问数据库的缓冲:当从数据库读取数据时,会首先从Buffer Pool中读取,如果Buffer Pool中没有,则从磁盘读取后放入Buffer Pool;当向数据库写入数据时,会首先写入Buffer Pool,Buffer Pool中修改的数据会定期刷新到磁盘中(这一过程称为刷脏)。

不过这也带来了一个新的问题,如果MySQL宕机,而此时Buffer Pool中修改的数据还没有刷新到磁盘,就会导致数据的丢失,事务的持久性无法保证。

为了解决这个问题就引入了redo log,也叫重做日志。当数据修改时,除了修改Buffer Pool中的数据,还会在redo log记录这次操作;当事务提交时,会调用fsync接口对redo log进行刷盘。如果MySQL宕机,重启时可以读取redo log中的数据,对数据库进行恢复。redo log采用的是WAL(Write-ahead logging,预写式日志),所有修改在提交前先写入日志,保证了数据不会因MySQL宕机而丢失,从而满足了持久性要求。redo log是针对物理页的,并发执行,最后一次提交会覆盖未提交的数据。本地redo log:

redo log也是有缓冲区的——redo log buffer,当事务提交之后会把所有修改信息都刷新到磁盘上。用户也可以通过控制通过变量 innodb_flush_log_at_trx_commit 的值来修改刷新策略(默认1),如设置值为2,控制成每秒刷新,这样事务提

交就会较快,不过可能面临日志丢失的风险。

redo log是在SQL语句执行之后记录的。

既然redo log也需要存储,也涉及磁盘IO为啥还用它?

(1)redo log 的存储是顺序存储,而缓存同步是随机操作。

(2)缓存同步是以数据页为单位的,每次传输的数据大小大于redo log。

redo log是用来恢复数据的 用于保障已提交事务的持久化特性。

隔离性:

原理:
(1). 写操作对写操作的影响:锁机制保证隔离性
(2). 写操作对读操作的影响:MVCC保证隔离性

一致性:

一致性比较特殊,前面的原子性、持久性和隔离性都是为一致性服务的,除此之外,一致性还依赖于数据库自我提供的保障,如SQL语法验证,列类型插入数据类型验证,同时也依赖于应用层的保障,如转账操作,需要开发人员进行转账者的余额扣除和接受者的余额增加,如果应用层面出现问题,那么一致性也是无法保障的。

二、隔离级别底层原理浅析

在事务底层原理浅析中,关于隔离性的原理没有过多深入,在此我们简单介绍一下。

首先介绍一下mysql的MVCC(MultiVersion Concurrency Control) 叫做多版本并发控制。它是依赖undo logread view实现的。undo log上文已经介绍过了,不再赘述,read view(可读视图),这与我们平时理解的数据库视图不同,它是用来判断当前数据版本的可见性的。

readview主要有四个属性:

(1). m_ids 代表生成ReadView时,当前所有活跃的事务ID,活跃的意思就是事务开启了还没提交;

(2). min_trx_id 表示当前活跃的mIds中最小的事务ID;

(3). max_trx_id 表示生成ReadView时,最大的事务ID,它不一定是mIds中最大的事务ID;

(4).creator_trx_id表示创建该ReadView的事务ID。

注意:每开启一个事务,事务ID就自增一次,事务ID可以看做一个全局自增变量。最先开启的事务不一定比后开启的事务先提交,比如长连接,所以不要认为max_trx_id就是mIds中的最大值。

read view是怎样借助上面四个属性,判断事务应该读取那个版本的数据呢?

如果被访问版本的 data_trx_id 小于 m_ids 中的最小值,说明生成该版本的事务在 ReadView 生成前就已经提交了,那么该版本可以被当前事务访问。

如果被访问版本的 data_trx_id 属性值与ReadView中的creator_trx_id值相同,意味着当前事务在访问它自己修改过的记录,所以该版本可以被当前事务访问。

如果被访问版本的 data_trx_id 属性值大于ReadView中的max_trx_id值,表明生成该版本的事务在当前事务生成ReadView后才开启,所以该版本不可以被当前事务访问。

如果被访问版本的 data_trx_id 属性值在ReadView的min_trx_id和max_trx_id之间,那就需要判断一下trx_id属性值是不是在m_ids列表中,如果在,说明创建ReadView时生成该版本的事务还是活跃的,该版本不可以被访问;如果不在,说明创建ReadView时生成该版本的事务已经被提交,该版本可以被访问。

当一个事务要读取一行数据,首先用上面规则判断数据的最新版本也就是那行记录,如果发现可以访问就直接读取了,如果发现不能访问,就通过DATA_ROLL_PTR指针找到undo log,递归往下去找每个版本,知道读取到自己可以读取的版本为止,如果读取不到就返回空。

所以访问数据时,数据库里面会创建一个视图,访问的时候以视图的逻辑结果为准:

READ UNCOMMITED (未提交读):此隔离级别下直接返回记录上的最新值,没有视图概念。因为读不会加任何锁,所以写操作在读的过程中修改数据,所以会造成脏读。好处是可以提升并发处理性能,能做到读写并行。

READ COMMITED (提交读):此隔离级别下,这个视图是在每个 SQL语句开始执行的时候创建的。InnoDB在 READ COMMITTED,使用排它锁,读取数据不加锁而是使用了MVCC机制。或者换句话说他采用了读写分离机制。

REPEATABLE READ (可重复读):此隔离级别下,这个视图是在事务启动时创建的,整个事务存在期间都用这个视图。

SERIALIZABLE (串行化):此隔离级别下直接用加锁的方式来避免并行访问。

写到这里,你也许发现了,MySQL中借助MVCC在可重复读隔离级别下其实也杜绝了幻读的发生。

三、总结

原子性:使用 undo log (回滚日志)实现回滚,从而保障未提交事务的原子性;

持久性:使用 redo log(重做日志)实现数据恢复,从而保障已提交事务的持久性;

隔离性:使用锁以及MVCC思想实现读写分离,读读并行,读写并行;

一致性:通过回滚、恢复和在并发环境下的隔离做到一致性。

到此这篇关于mysql事务和隔离级别底层原理浅析的文章就介绍到这了,更多相关mysql事务和隔离级别内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • mysql事务隔离级别详情

    serializable 串行化(无问题) 事务必须以顺序的方式执行,前一个事务提交之前后面的事务无法进行提交,最安全,但是不能并发操作,导致效率低下. repeatab read 可重复读(默认隔离级别)(幻读) 在一个事务未提交之前,里面不论执行多少次查询,查询的结果都一样(即使这条记录被别的事务修改过)但是可能会出现幻读 read committed 读已提交(不可重复度,幻读) 在当前事务中别的事务提交的数据可以看到,那么可能会导致不可重复读(另一个线程提交数据后当前线程可以看到,然后就

  • Mysql案例刨析事务隔离级别

    目录 1. 理论 SERIALIZABLE REPEATABLE READ READ COMMITTED READ UNCOMMITTED 2. SQL 实践 2.1 查看隔离级别 2.2 READ UNCOMMITTED 2.2.1 准备测试数据 2.2.2 脏读 2.2.3 不可重复读 2.2.4 幻象读 2.3 READ COMMITTED 2.4 REPEATABLE READ 2.5 SERIALIZABLE 3. 总结 很多小伙伴对 MySQL 的隔离级别一直心存疑惑,其实这个问题一

  • 简述MySql四种事务隔离级别

    隔离级别: 隔离性其实比想象的要复杂. 在SQL标准中定义了四种隔离级别, 每一个事务中所做的修改,哪些在事务内和事务间是可见的,哪些是不可见的.较低级别的隔离通常可以执行更高的并发,系统的开销也更低. 下面简单地介绍一下四种隔离级别. 1.READ UNCOMMITTED(未提交读) 在 READ UNCOMMITTED级别, 事务中的修改, 即使没有提交, 对其他事务也都是可见的. 事务可以读取未提交的数据, 这也被称为脏读 (Dirty Read). 这个级别会导致很多问题,从性能上来说,

  • mysql事务和隔离级别底层原理浅析

    目录 前言 一.事务底层原理浅析 原子性: 持久性 隔离性: 一致性: 二.隔离级别底层原理浅析 三.总结 前言 首先回顾一下什么是事务,事务是数据库操作的最小工作单元,是作为单个逻辑工作单元执行的一系列操作:这些操作作为一个整体一起向系统提交,要么都执行.要么都不执行:事务是一组不可再分割的操作集合(工作逻辑单元). 事务的特性: 原子性(Atomicity):原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚.一致性(Consistency):事务执行的结果必须是使数据库从一个一致性

  • 详解MySQL事务的隔离级别与MVCC

    事务隔离级别 事务并发执行遇到的问题 脏写 如果一个事务修改了另一个未提交事务修改过的数据,那就意味着发生了脏写 脏读 如果一个事务读到了另一个未提交事务修改过的数据,那就意味着发生了脏读 不可重复读 如果一个事务只能读到另一个已经提交的事务修改过的数据,并且其他事务每对该数据进行一次修改并提交后,该事务都能查询到最新值,那就意味着发生了不可重复读 幻读 如果一个事务先根据某些条件查询出一些记录,之后另一个事务又向表中插入了符合这些条件的记录,原先的事务再次按照该条件查询时,能把另一个事务插入的

  • MYSQL事务的隔离级别与MVCC

    目录 前言 1. 事务(transaction)的起源 1.1. 事务的定义 1.2. 哪些存储引擎支持事务 2. MySQL的事务语法 2.1. 自动提交 2.2. 手动操作事务 2.2.1. 开启事务 2.2.2. 提交或回滚 2.3. autocommit系统变量 3. 事务并发执行导致的读问题 3.1. 脏读 3.2. 不可重复读 3.3. 幻读 4. 回答一些可能存在的问题 5. SQL标准与4种隔离级别 5.1. 为什么要设置隔离级别? 5.2. 蹩脚的中文翻译 5.3. 为什么单单

  • MySQL事务的隔离级别详情

    目录 一.隔离级别的概念 二.测试TRANSACTION_READ_UNCOMMITTED隔离级别 三.测试TRANSACTION_READ_COMMITTED隔离级别 四.测试TRANSACTION_REPEATABLE_READ隔离级别 五.测试TRANSACTION_SERIALIZABLE隔离级别 一.隔离级别的概念 为什么要考虑隔离级别? 因为事务要并发执行,而并发执行可能会出现一些问题:脏读.不可重复读和虚读,有的是允许出现的,有的不允许出现,对于这种不同程度上的出现或不出现的并发控

  • Mysql事务的隔离级别(脏读+幻读+可重复读)

    目录 一.事务 (一)什么是事务 (二)事务的特征 (三)手动开启.提交.回滚事务 二.脏读.幻读.可重复读 (一)脏读 read uncommit (二)不可重复读 unrepeatable (三)幻读 (四)不可重复读和幻读的区别 三.事务的隔离级别 (一)读未提交read uncommitted (二)读已提交read committed (三)不可重复读 read repeatable (四)序列化 serializable 前言: 因为InnoDB是支持事务的,所以只对InnoDB的事

  • MySQL事务及Spring隔离级别实现原理详解

    1.事务具有ACID特性 原子性(atomicity):一个事务被事务不可分割的最小工作单元,要么全部提交,要么全部失败回滚. 一致性(consistency):数据库总是从一致性状态到另一个一致性状态,它只包含成功事务提交的结果 隔离型(isolation):事务所做的修改在最终提交一起,对其他事务是不可见的 持久性(durability):一旦事务提交,则其所做的修改就会永久保存到数据库中. 2.事务的隔离级别 1)隔离级别的定义与问题 READ UNCOMMITTED(读未提交):事务的修

  • MySQL脏读幻读不可重复读及事务的隔离级别和MVCC、LBCC实现

    目录 前言 事务因并发出现的问题有哪些 脏读 不可重复读 幻读 不可重复读与幻读的区别 事务的四个隔离级别 InnoDB默认的隔离级别是RR Read UnCommited 读未提交 RU Read Commited 读已提交 RC Repeatable Read 可重复读 RR Serializable 串行化 undo 版本链 read view MVCC(Multi-Version Concurrent Control )多版本并发控制 可重复读实现 读已提交实现 LBCC 锁的类型 共享

  • mysql的事务,隔离级别和锁用法实例分析

    本文实例讲述了mysql的事务,隔离级别和锁用法.分享给大家供大家参考,具体如下: 事务就是一组一起成功或一起失败的sql语句.事务还应该具备,原子性,一致性,隔离性和持久性. 一.事务的基本要素 (ACID) 1.原子性:事务开始后,所有的操作,要么全部成功,要么全部失败,不可能处于中间状态,事务是一个不可分割的整体,就像原子一样. 2.一致性:事务开始前和结束后,数据库的完整性约束没有破坏,A向B转账,A扣了钱,但B却没到账. 3.隔离性:同时发生的事务(并发事务)不应该导致数据库处于不一致

  • mysql+Spring数据库隔离级别与性能分析

    这里以mysql为例,先明确以下几个问题: 一.一般项目如果不自己配置事务的话,一般默认的是autocommit,即执行完一个操作后自动commit,提交事务. (注:事务是绑定在数据库操作上的,也就是当程序执行(statement.excute等操作)转而到数据库层面上的时候,事务才开始发生)当然spring可以将几个数据库操作动作绑在一个事务中,这样就需要介绍下spring事务配置方法,下面介绍的是常用方法,其他方法网上有很多.spring提供了很多事务配置的策略,很方便,简要介绍一下: 复

  • MySQL事务的隔离性是如何实现的

    目录 并发场景 写-写 读-读 读-写 和 写-读 MySQL中的锁 行级锁 表级锁 隔离级别 Read Committed Repeatable Read 参考博客 并发场景 最近做了一些分布式事务的项目,对事务的隔离性有了更深的认识,后续写文章聊分布式事务.今天就复盘一下单机事务的隔离性是如何实现的? 隔离的本质就是控制并发,如果SQL语句就是串行执行的.那么数据库的四大特性中就不会有隔离性这个概念了,也就不会有脏读,不可重复读,幻读等各种问题了 对数据库的各种并发操作,只有如下四种,写写,

随机推荐