本文不再阐述数据库的ACID,请了解后再来阅读此文!

一、Mysql中的锁

首先我们要知道mysql锁,锁住的是索引,当不设置索引的时候会将隐藏字段设置为索引,且隐藏字段默认走全表扫描,所以当不设置主键索引,且表中无其他索引(不包括隐藏字段)时,会锁全表。
下面,我们具体来了解一下Mysql中具体有哪些锁以及锁的作用:

Shared Locks(共享锁/S锁)

若事务T对数据对象A加上S锁,则事务T只能读A;其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。这就保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。

Exclusive Locks(排它锁/X锁)

若事务T对数据对象A加上X锁,则只允许T读取和修改A,其它任何事务都不能再对A加任何类型的锁,直到T释放A上的锁。它防止任何其它事务获取资源上的锁,直到在事务的末尾将资源上的原始锁释放为止。在更新操作(INSERT、UPDATE 或 DELETE)过程中始终应用排它锁。

注意:排他锁会阻止其它事务再对其锁定的数据加读或写的锁,但是不加锁的就没办法控制了。

Record Locks(记录锁)

记录锁,顾名思义,是加在具体某条记录上的锁。比如select * from user where id=1 and id=10 for update,就会在id=1和id=10的索引行上加Record Lock。

Gap Locks(间隙锁)

间隙锁,它会锁住两个索引之间的区域。比如select * from user where id>1 and id<10 for update,就会在id为(1,10)的索引区间上加Gap Lock。

Next-Key Locks(临界锁)

也叫间隙锁,它是Record Lock + Gap Lock形成的一个闭区间锁。比如select * from user where id>=1 and id<=10 for update,就会在id为[1,10]的索引闭区间上加Next-Key Lock。

此外,还有Innodb自带的两种锁,只能由系统自己添加
意向共享锁和意向排他锁
作用:查看该表是否之前已经加了共享或者排他锁提高加表锁的效率,这样在加表锁之前就不用全表扫描是否有数据已经加了共享锁或者是排他锁。

二、MVCC

在了解MVCC之前,首先来先了解一下Mysql中的日志:undo log和redo log
undo log会记录在未执行操作前mysql数据的状态
redo log会记录新数据的备份,将数据恢复到最新状态

回到重点,什么是MVCC?

1.MVCC (Multiversion Concurrency Control) 中文全称叫 多版本并发控制 ,是现代数据库(包括 MySQL 、 Oracle 、 PostgreSQL 等)引擎实现中常用的处理读写冲突的手段, 目的在于提高 数据库 高并发场景下的吞吐性能 。如此一来不同的事务在并发过程中, SELECT 操作可以不加锁而是通过 MVCC 机制读取指定的版本历史记录,并通过一些手段保证保证读取的记录值符合事务所处的隔离级别,从而解决并发场景下的读写冲突。

2.InnoDB 中 MVCC 的实现方式为:每一行记录都有两个隐藏列: trx_id 、roll_ptr (如果没有主键,则还会多一个隐藏的主键列row_id)。

Trx_id
记录最近更新这条行记录的事务 ID ,大小为6个字节

Roll_ptr
表示指向该行回滚段 (rollback segment) 的指针,大小为 7 个字节, InnoDB 便是通过这个指针找到之前版本的数据。该行记录上所有旧版本,在 undo 中都通过链表的形式组织。

Row_id
行标识(隐藏单调自增 ID ),大小为 6 字节,如果表没有主键, InnoDB 会自动生成一个隐藏主键,因此会出现这个列。另外,每条记录的头信息( record header )里都有一个专门的 bit ( deleted_flag )来表示当前记录是否已经被删除。

在多个事务并行操作某行数据的情况下,不同事务对该行数据的 UPDATE 会产生多个版本,然后通过回滚指针组织成一条 Undo Log 链,这节我们通过一个简单的例子来看一下 Undo Log 链是如何组织的,Trx_id和 Roll_ptr两个参数在其中又起到什么样的作用?
1)对Row_id= 1 的这行记录加排他锁
2)把该行原本的值拷贝到undo log 中,Trx_id 和Roll_ptr都不动
3)修改该行的值这时产生一个新版本,更新Trx_id为修改记录的事务 ID ,将 Roll_ptr指向刚刚拷贝到undo log 链中的旧版本记录,这样就能通过Roll_ptr找到这条记录的历史版本。如果对同一行记录执行连续的 UPDATE , Undo Log 会组成一个链表,遍历这个链表可以看到这条记录的变迁
4)记录 redo log ,包括 undo log 中的修改

那么 INSERT 和 DELETE 会怎么做呢?其实相比 UPDATE 这二者很简单, INSERT 会产生一条新纪录,它的Trx_id为当前插入记录的事务 ID ; DELETE 某条记录时可看成是一种特殊的 UPDATE ,其实是软删,真正执行删除操作会在 commit 时,Trx_id则记录下删除该记录的事务 ID 。

而下面所说的已提交读和可重复读的区别就在于它们生成ReadView的策略不同。
3.实现一致性读----ReadView

1)RC下ReadView的生成

在 RC 隔离级别下,每个 SELECT 语句开始时,都会重新将当前系统中的所有的活跃事务拷贝到一个列表生成 ReadView 。二者的区别就在于生成 ReadView 的时间点不同,一个是事务之后第一个 SELECT 语句开始、一个是事务中每条 SELECT 语句开始。

ReadView 中是当前活跃的事务 ID 列表,称之为 m_ids ,其中最小值为 up_limit_id ,最大值为 low_limit_id ,事务 ID 是事务开启时 InnoDB 分配的,其大小决定了事务开启的先后顺序,因此我们可以通过 ID 的大小关系来决定版本记录的可见性,具体判断流程如下:

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

2.如果被访问版本的 trx_id 大于 m_ids 列表中的最大值 low_limit_id ,说明生成该版本的事务在生成 ReadView 后才生成,所以该版本不可以被当前事务访问。需要根据 Undo Log 链找到前一个版本,然后根据该版本的 trx_id 重新判断可见性。

3.如果被访问版本的 trx_id 属性值在 m_ids 列表中最大值和最小值之间(包含),那就需要判断一下 trx_id 的值是不是在 m_ids 列表中。如果在,说明创建 ReadView 时生成该版本所属事务还是活跃的,因此该版本不可以被访问,需要查找 Undo Log 链得到上一个版本,然后根据该版本的 DB_TRX_ID 再从头计算一次可见性;如果不在,说明创建 ReadView 时生成该版本的事务已经被提交,该版本可以被访问。

4.此时经过一系列判断我们已经得到了这条记录相对 ReadView 来说的可见结果。此时,如果这条记录的 delete_flag 为 true ,说明这条记录已被删除,不返回。否则说明此记录可以安全返回给客户端。

2)RR下ReadView的生成

在 RR 隔离级别下,每个事务 touch first read 时(本质上就是执行第一个 SELECT 语句时,后续所有的 SELECT 都是复用这个 ReadView ,其它 update , delete , insert 语句和一致性读 snapshot 的建立没有关系),会将当前系统中的所有的活跃事务拷贝到一个列表生成 ReadView 。
下图中事务 A 第一条 SELECT 语句在事务 B 更新数据前,因此生成的 ReadView 在事务 A 过程中不发生变化,即使事务 B 在事务 A 之前提交,但是事务 A 第二条查询语句依旧无法读到事务 B 的修改。

下图中,事务 A 的第一条 SELECT 语句在事务 B 的修改提交之后,因此可以读到事务 B 的修改。 但是注意,如果事务 A 的第一条 SELECT 语句查询时,事务 B 还未提交,那么事务 A 也查不到事务 B 的修改。

3)举例
举个例子:
RC下的MVCC判断流程
我们现在回看刚刚的查询过程,为什么事务 B 在 RC 隔离级别下,两次查询的 x 值不同。 RC 下 ReadView 是在语句粒度上生成的。

当事务 A 未提交时,事务 B 进行查询,假设事务 B 的事务 ID 为 300 ,此时生成 ReadView 的 m_ids 为 [200,300],而最新版本的 trx_id 为 200 ,处于 m_ids 中,则该版本记录不可被访问,查询版本链得到上一条记录的 trx_id 为 100 ,小于 m_ids 的最小值 200 ,因此可以被访问,此时事务 B 就查询到值 10 而非 20 。
待事务 A 提交之后,事务 B 进行查询,此时生成的 ReadView 的 m_ids 为 [300],而最新的版本记录中 trx_id 为 200 ,小于 m_ids 的最小值 300 ,因此可以被访问到,此时事务 B 就查询到 20

RR下的MVCC判断流程
如果在 RR 隔离级别下,为什么事务 B 前后两次均查询到 10 呢? **RR 下生成 ReadView 是在事务开始时,m_ids 为 [200,300],后面不发生变化,**因此即使事务 A 提交了, trx_id 为 200 的记录依旧处于 m_ids 中,不能被访问,只能访问版本链中的记录 10

该段参考自:https://www.codercto.com/a/88775.html

三、事务隔离级别的实现(综合运用锁和MVCC)

事务隔离机制的实现主要分以下两种实现方式:

1.在读取数据前,对其加锁,阻止其他事务对数据进行修改,即LBCC
2.生成一个数据请求时间点的一致性数据快照,并用快照来提供一定级别的一致性读取,即MVCC

事务隔离机制的实现

1.READ COMMITTED:InnoDB在该隔离级别(READ COMMITTED)写数据时,使用排它锁, 读取数据之前必须先对其加共享锁,读完后即可释放共享锁。保证读取时数据不被修改,从而避免“脏读”。或者不加锁而是使用了MVCC机制。
2.REPEATABLE READ:同样,InnoDB在该隔离级别(REPEATABLE READ)写数据时,使用排它锁, 读取数据读取数据之前必须先对其加共享锁,直到事务结束才释放锁。等到事务结束才释放这样就能保证可重复读。或者不加锁而是使用了MVCC机制。
而这两种机制的MVCC具体实现参考第二点
因为不管是共享锁还是排他锁都只针对修改数据时的情况,但是并不针对增加,删除的情况,故两种情况都会产生“幻读”。
(实际上,为了实现高并发性,在读的时候一般不加锁,而是使用MVCC机制)
3.SERIALISABLE:该级别下,会自动将所有普通select转化为select … lock in share mode执行,即针对同一数据的所有读写都变成互斥的了,可靠性大大提高,并发性大大降低。

===============================================================================
此外,还有以下补充点:
事务的原子性是通过undo log来实现
事务的持久性是通过redo log来实现
事务的隔离性是通过读写锁+MVCC来实现
事务的一致性是通过原子性,隔离性,持久性来实现

讨论:曾在一些视频中看到:“实际操作中InnodB在可重复读就已经解决幻读”,原因是Innodb在可重复读使用了临界锁解决了幻读问题,大家觉得对不对呢?

欢迎在评论区留下原因+看法

Mysql的锁以及MVCC解决事务隔离级别相关推荐

  1. mysql mvcc 读写阻塞_mysql面试题MVCC原理事务隔离级别_aiailingfei的博客-CSDN博客

    原文作者:小小一只鸟 原文标题:mysql面试题MVCC原理事务隔离级别 发布时间:2021-01-19 19:43:38 mysql事务隔离级别可重复读面试题 熊大 话说今天漂亮的妹子给我发过一张图 ...

  2. mysql读写分离主从原理、事务隔离级别及使用、锁表和锁行场景、乐观锁和悲观锁、lock锁和sychronized区别及使用自己学习之后总结和参考一些博客感觉系统了解了

    synchronized与Lock的区别 两者区别: 1.首先synchronized是java内置关键字,在jvm层面,Lock是个java类: 2.synchronized无法判断是否获取锁的状态 ...

  3. 服务器无法执行该事务_分布式事务、MVCC、事务隔离级别

    我们都知道,OceanBase 是一个分布式数据库,数据是打散到多台服务器上的,当一个分布式事务要执行的时候,可能需要跨越多台 OB Server,如果在执行过程中遇到各种各样的异常情况,OceanB ...

  4. mysql 消极锁_MySQL支持的事物隔离级别以及消极锁和乐观锁原理和应用场景

    在一样平常开发中,尤其是营业开发,少不了行使 Java 对数据库举行基本的增删改查等数据操作,这也是Java工程师的必备手艺之一.做好数据操作,不仅仅需要对Java语言相关框架的掌握,更需要对种种数据 ...

  5. 3分钟搞懂MySQL事务隔离级别及SET TRANSACTION影响事务

    导读:MySQL支持SQL:1992标准中的所有事务隔离级别,使用SET TRANSACTION来设置不同的事务隔离级别或访问模式,我们一起实战下它的效果. 我们都知道,MySQL的内置引擎中只有In ...

  6. 概述MySQL数据库---事务隔离级别

    同一个应用程序中的多个事务或不同应用程序中的多个事务在同一个数据集上并发执行时, 可能会出现许多意外的问题,事务并发处理可能引起的问题可分为如下三种类型: 脏读(Drity Read): 已知有两个事 ...

  7. mysql隔离级别 简书_InnoDB 事务隔离级别(Mysql篇)

    前言: Mysql支持MyISAM和InnoDB两种存储引擎,区别在此就不详细说明.此篇是讲述事务,所以切记自己的table是InnDB.此处大坑! 在Mysql InnoDB 中,事务主要有四种隔离 ...

  8. mysql innodb 默认隔离级别_MySQL Innodb 事务隔离级别

    在Mysql中,事务主要有四种隔离级别,今天我们主要是通过示例来比较下,四种隔离级别实际在应用中,会出现什么样的对应现象. Read uncommitted (未提交读) Read committed ...

  9. 【概念原理】四种SQL事务隔离级别和事务ACID特性

    2019独角兽企业重金招聘Python工程师标准>>> 事务是一组读写操作,并且具有只有所有操作都成功才算成功的特性. 事务隔离级别 SQL事务隔离级别由弱到强分别是:READ_UN ...

最新文章

  1. HBase 与 MapReduce 集成
  2. Spring(四)Bean注入方试
  3. vue.js响应式原理解析与实现
  4. excel 中的文本是ansi还是unicode_详细讲解Excel中常用的文本函数
  5. GROUP BY 和SUBSTRING 的配合使用
  6. GridView 中添加删除确认提示框
  7. [转]Android Service Test——简单测试例子
  8. php 5.6 闭包,PHP 闭包那点事儿
  9. 当跨国企业女职业经理人遇上创业女 CEO,两者会擦出什么样的火花?
  10. getHandel redis_Controller层利用Redis实现分布式锁(注解实现)
  11. extmail如何登陆mysql_linux下ExtMail邮件使用及管理平台
  12. 数据库管理系统的基本组成
  13. ClientToScreen ()与 ScreenToClient()
  14. 【股票融资融券模拟交易系统】开发与设计
  15. Badboy内置浏览器,提示脚本错误解决方法
  16. 用python画星空-用python画星空源代码是什么?
  17. Oracle05:什么是OCP认证
  18. 中国新一代人工智能治理原则发布 | 发展负责任的人工智能
  19. POJ 2942 圆桌骑士
  20. 电子信息工程专业就业形势分析

热门文章

  1. 一个刁刁的卡片样式广告轮播
  2. [转]用Eclipse进行可视化Java界面设计
  3. 喝不完的杯中酒,割不尽的名人头
  4. 5G工业物联网环境下多方认证性能评估
  5. RFID手持机助力仓储物流信息化管理
  6. 机器学习()PR曲线绘制
  7. html利用百度地图查找路线,html调用百度地图API实现查找路线
  8. 第一阶段:JAVA快速入门
  9. 《途客圈创业记:不疯魔,不成活》一一2.4 与iWeekend再续前缘
  10. linux动态库注册函数,linux下加载动态库函数