mysql mvcc 隔离级别_关于 Mysql 四种隔离级别中 Lock 和 MVCC 的关系

读写锁

共享锁(share lock)| 读锁(read lock)

读锁是共享的,或者说是相互不阻塞的。多个客户在同一时刻可以同时读取同一个资源,而互不干扰

SELECT ... LOCK IN SHARE MODE

排他锁(exclusive lock)| 写锁(write locl)

写锁则是具有排他性,也就是说一个写锁会阻塞其他的写锁和读锁,只有这样,才能确保在给定的时间里,只有一个用户能执行写入,并防止其他用户读取正在写入的同一资源

SELECT ... FOR UPDATE

锁粒度

表锁(table lock)

对整张表进行控制

行级锁(row lock)

对一行数据进行控制

多版本并发控制(MVVC)

大多数事物行存储引擎实现的都不是简单的行级锁。基于提神并发性能的考虑,它们一般都同时实现了多版本并发控制。

MVCC 的实现,是通过保存数据在某一时间点的快照来实现。也就是说,不管需要执行多长时间,每个事物看到的数据都是一致的。根据事物开始的时间不同,每个事物对同一张表,同时刻看到的数据可能是不一致的。

Msql InnoDB 的 MVCC,是通过在每行记录后面保存两个隐藏的列来实现。这两个列,一个保存列行的创建时间,一个保存行的过期时间(删除时间)。当然存储的并不是实际的时间值,而是系统版本号。每开始一个新的事物,系统版本号都会自动递增。事物开始时刻的系统版本号会作为事物的版本号,用来查询到每行记录的版本号进行比较。

SELECT

InnoDB 会根据以下两个条件检查每行记录:

InnoDB 只查找版本早于当前事物版本的数据行(也就是,行的系统版本号小于或等于事物的系统版本号),这样可以确保事物读取的行,要么是在事物开始前已存在的,要么是事物自身插入或者修改过的。

行的删除版本要么未定义,要么大于当前事物版本号。这可以确保事物读取到的行,在事物开始之前未被删除。

只有符合上述两个条件的记录,才能返回作为查询结果

INSERT

InnoDB 为新插入的每一行保存当前系统版本号作为行版本号

DELETE

InnoDB 为删除的每一行保存当前系统版本号作为行删除标识

UPDATE

InnoDB 为插入一行新记录,保存当前系统版本号作为行版本号,同时保存当前系统版本号到原来的行作为行删除标识

总结

保存这两个额外系统版本号,使大多数读操作都可以不用加锁。这样设计使得读数据操作很简单,性能很好,并且也能够保证只会读取到符合标准的行,不足之处是每行都要额外的储存空间,需要做更多的行检查工作,以及额外的维护工作。

MVCC 只在 REPEATABLE READ 和 READ COMMITTED 两个隔离级别下工作。其他两个隔离级别都和 MVCC 不兼容,因为 READ UNCOMMITTED 总是读取最新的数据行,而不是符合当前事物版本的数据行。而 SERIALIZABLE 则会对所有读取的行都加锁

隔离级别

READ UNCOMMITTED(未提交读)

事物可以读取未提交的数据(脏读)

READ COMMITTED(提交读)

只能看见已经提交的事物所做的修改(不可重复读)

REPEATABLE READ(可重复度)(默认隔离级别)

当前事物在读取某个范围内的记录时,另外一个事物又在该范围内插入了新的记录,当前事物再次查询时,会产生幻行(幻读)

SERIALIZABLE(可串行化)

在读取的每一行数据上都加锁(排他锁)

隔离级别

脏读

不可重复读

幻读

加锁读

READ UNCOMMITTED

YES

YES

YES

NO

READ COMMITTED

NO

YES

YES

NO

REPEATABLE READ

NO

NO

YES

NO

SERIALIZABLE

NO

NO

NO

YES

PS:

乐观锁

乐观锁大多是基于数据版本记录机制实现,一般是给数据库表增加一个"version"字段。读取数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。

悲观锁

悲观锁依靠数据库提供的锁机制实现。MySQL 中的共享锁和排它锁都是悲观锁。数据库的增删改操作默认都会加排他锁,而查询不会加任何锁。

补充

当前读、快照读,record lock(记录锁)、gap lock(间隙锁)、next-key lock

本来只有 SERIALIZABLE 隔离级别才可以解决幻读问题,而实际上由于快照读的特性使可重复读也解决了幻读问题。

当前读是因为 innodb 默认为它加入了间隙锁,防止在事务期间对相关数据集插入记录,从而避免出现幻读。

在 RR 级别下,快照读是通过 MVVC(多版本控制)和 undo log 来实现的,当前读是通过加 record lock(记录锁)和 gap lock(间隙锁)来实现的。如果需要实时显示数据,还是需要通过手动加锁来实现。这个时候会使用 next-key 技术来实现。

在 MySQL 中,提供了两种事务隔离技术,第一个是 mvcc,第二个是 next-key 技术。这个在使用不同的语句的时候可以动态选择。不加 lock inshare mode 之类的快照读就使用 mvcc。否则 当前读使用 next-key。mvcc 的优势是不加锁,并发性高。缺点是不是实时数据。next-key 的优势是获取实时数据,但是需要加锁。

Record lock

单条索引记录上加锁,record lock 锁住的永远是索引,而非记录本身,即使该表上没有任何索引,那么 innodb 会在后台创建一个隐藏的聚集主键索引,那么锁住的就是这个隐藏的聚集主键索引。所以说当一条 SQL 没有走任何索引时,那么将会在每一条聚集索引后面加 X 锁,这个类似于表锁,但原理上和表锁应该是完全不同的。

Gap Lock

在索引记录之间的间隙中加锁,或者是在某一条索引记录之前或者之后加锁,并不包括该索引记录本身。gap lock 的机制主要是解决可重复读模式下的幻读问题。

Next-Key Lock

行锁和间隙锁组合起来就叫 Next-Key Lock。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/422237.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python三级联动菜单_VUE+element三级联动或树形菜单获取最后一项,并加入到表格中...

如下图,要实现的功能如下,勾选三级联动的材料,勾选最后一级的材料,把勾选的材料信息动态添加到下面表格中1 data数据return {options:[], // 三级联动 数据optionsObj : {} //{id: item} 材料id键值对clList: [], // 选中的材料}2 从后台获取三级联动数据getDataTrees(){this.s…

开博声明

首先想说的是博客园的博客一键搬家功能真不错,很方便的把CSDN上的旧博文搬家过来了,虽然只有区区几篇,但是敝帚自珍嘛。 在这里开博的原因有几个方面,一是随着工作年限的增加,越来越感觉到平时积累的重要性&#xff0c…

前端学习(542):node得环境搭建

进入官网下载 node.js 建立一个文件夹 直接下一步,下一步 安装完成以后 winr 安装完成 建立一个js文件 找到路径 运行

python语言是非跨平台语言吗_python是跨平台的语言吗

Python是跨平台的,免费开源的一门计算机编程语言。是一种面向对象的动态类型语言,最初被设计用于编写自动化脚本(shell),随着版本的不断更新和语言新功能的添加,越来越多被用于独立的、大型项目的开发。支持常见的主流平台&#x…

技术人员,你拿什么拯救你的生活----温水煮青蛙

有时候,我常常问自己这样一个问题:如何哪天你不搞技术了,你还可以干什么?还能够用什么来养活自己和家人?很多的朋友看到这个问题之后可以给出很多的答案,例如转管理,自主创业,实在不…

用python直接调用asr技术_语音识别技术ASR(一)基本概念

注:本文内容主要来源自台大李宏毅老师的Deep Learning for Human Language Processing系列课程一、语音识别的基本过程语音识别的输入一般是时域的语音信号,数学上用一系列向量表示(length T, dimension d),输出是文本,用一系列to…

前端学习(544):node的全局模块

//console.log(process.env);let num1parseInt(process.argv[2]) let num2parseInt(process.argv[3])console.log(num1num2);运行

C#笔记(五):文件和流

我们可以知道,在System.IO 命名空间下提供了一系列的类,我们可以通过相应的类进行文件、目录、数据流的操作。System.IO 命名空间 原理:.NET Framework封装了一系列底层的方法,有些直接与Windows API打交道。那么例如创建文件&…

MySql中游标的定义与使用方式_数据库系列:MySql中游标的定义与使用方式

创建游标首先在MySql中创建一张数据表:CREATE TABLE IF NOT EXISTS store (id int(11) NOT NULL AUTO_INCREMENT,name varchar(20) NOT NULL,count int(11) NOT NULL DEFAULT 1,PRIMARY KEY (id)) ENGINEInnoDB DEFAULT CHARSETlatin1 AUTO_INCREMENT7;INSERT INTO …

前端学习(545):node的系统模块require

let path require(path);console.log(path.dirname(/node/a/b/c/1.jpg)); console.log(path.basename(/node/a/b/c/1.jpg)); console.log(path.extname(/node/a/b/c/1.jpg)); 运行结果

PHPUnit安装、用法、测试(三)

首先我装的是phpunit 3.6.12 上代码吧&#xff1a; <?php class DataTest extends PHPUnit_Framework_TestCase{public static function provider(){return array(array(0,0,0),array(0,1,1),array(1,0,1),array(1,1,2)); }/***dataProvider provider**/public function te…

oracle使用 union all 用自增序列_值得收藏的Oracle数据库性能优化

值得收藏的Oracle数据库性能优化年尾了&#xff0c;新的一波面试军又要开始了&#xff0c;被问到最多的可能就是性能优化&#xff0c;尤其是数据库性能优化&#xff0c;这个面试题不管是初中高级工程师都会被问到。因此我觉得下面31点ORACLE优化还是值得调几个去面试。也方便以…

CGContext转CC

0 CGContextRef context UIGraphicsGetCurrentContext(); 设置上下文1 CGContextMoveToPoint 开始画线2 CGContextAddLineToPoint 画直线4 CGContextAddEllipseInRect 画一椭圆4 CGContextSetLineCap 设置线条终点形状4 CGContextSetLineDash 画虚线4 CGContextAddRect 画一方…

java mysql blob 存储图片_Java操作mysql存储图片

http://bbs.chinaunix.net/archiver/tid-2289421.html1把图片当成一个二进制流就可以了。mysql中有可以存储很大的2进制流文件。用的类型是&#xff1a;我们要做的是将一张图片存入Mysql中,在Mysql中用Blob来存储图片和音频等大的数据项.Blob 按其容量可分为四种,分别为:tinybl…

前端学习(547):node的系统模块fs

let fs require(fs);fs.readFile(./a.txt,(err,data)>{if(err){console.log(err);}else{console.log(data.toString());} })fs.writeFile(b.txt,月薪2元,{flag:"a"},(err)>{if(err){throw err} })运行结果

微软发布Visual Studio 2012 示例代码浏览器

示例代码对于开发人员的重要性是不言而喻的。很多程序员往往通过示例代码着手学习一门技术。当开发人员遇到编码困难时也往往希望得到示例代码来解决疑难杂症。示例代码可谓是开发人员的良师益友&#xff0c;为程序员的学习和工作保驾护航。 微软一站式示例代码库&#xff0c;与…

maya python 创建求_如何使用python在Maya中创建列表

预期输出我想在Maya 2014中创建一个用户界面&#xff0c;其中包含图像中给定的图层和相机。我不知道该使用什么小部件。我尝试创建&#xff0c;代码如下所示。在import maya.cmds as cmdswindow cmds.window( title"Render", iconNameBTD,widthHeight(400,300),titl…

前端学习(548):node的自定义模块

demo4.js exports.a1; exports.b2; let c3; demo5.js const mod1require(./demo4);console.log(mod1.a); console.log(mod1.b); console.log(mod1.c); 运行结果