Mysql 中的MVCC原理,undo日志的依赖
原文点击:MVCC原理浅析
读锁:
也叫共享锁、S锁,若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S 锁。这保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。写锁:
又称排他锁、X锁。若事务T对数据对象A加上X锁,事务T可以读A也可以修改A,其他事务不能再对A加任何锁,直到T释放A上的锁。这保证了其他事务在T释放A上的锁之前不能再读取和修改A。表锁:
操作对象是数据表。Mysql大多数锁策略都支持(常见mysql innodb),是系统开销最低但并发性最低的一个锁策略。事务t对整个表加读锁,则其他事务可读不可写,若加写锁,则其他事务增删改都不行。行级锁:
操作对象是数据表中的一行。是MVCC技术用的比较多的,但在MYISAM用不了,行级锁用mysql的储存引擎实现而不是mysql服务器。但行级锁对系统开销较大,处理高并发较好。Autocommit:
mysql一个系统变量,默认情况下autocommit=1表示mysql把没一条sql语句自动的提交,而不用commit语句。所以,当要开启事务操作时,要把autocommit设为0,可以通过“set session autocommit=0; ”来设置MVCC: (MVCC,Multiversion Currency Control)
多版本并发控制。一般情况下,事务性储存引擎不是只使用表锁,行加锁的处理数据,而是结合了MVCC机制,以处理更多的并发问题。Mvcc处理高并发能力最强,但系统开销比最大(较表锁、行级锁),这是最求高并发付出的代价。
当使用锁(尤其排他锁-行锁)进行并发控制,开销是非常大的 ,而使用MVCC机制来做,能一定程度的代替行锁,就可以有效降低系统开销
InnoDB的MVCC,是通过在每行记录后面保存两个隐藏的列来实现的,这两个列,分别保存了这个行的创建时间,一个保存的是行的删除时间。这里存储的并不是实际的时间值,而是系统版本号(可以理解为事务的ID),没开始一个新的事务,系统版本号就会自动递增,事务开始时刻的系统版本号会作为事务的ID.
话外内容:############开始###############
InnoDB的内核,会对所有row数据增加三个内部属性:
1.DB_TRX_ID:一个6byte的标识,每处理一个事务,其值自动+1
下面提到的“创建时间”和“删除时间”记录的就是这个DB_TRX_ID的值
如insert、update、delete操作时,删除操作用1个bit表示。
DB_TRX_ID是最重要的一个,可以通过语句“show engine innodb status”来查找
2.DB_ROLL_PTR: 大小是7byte,指向写到rollback segment(回滚段)的一条undo log记录
(update操作的话,记录update前的ROW值)
3.DB_ROW_ID: 大小是6byte,该值随新行插入单调增加。
当由innodb自动产生聚集索引时聚集索引(即没有主键时,因为MYSQL默认聚簇表,会自动生成一个ROWID)
包括这个DB_ROW_ID的值,
不然的话聚集索引中不包括这个值,这个用于索引当中。
话外内容:############结束###############
如:列子,假设版本好初始为1
create table tb(
id int auto_increment primary key,
name cahr(32));
创建几条数据:insert 操作:第一个事务ID为1
start transaction;
insert into tb(name) values('shenjian') ;
insert into tb(name) values('zhangshan');
insert into tb(name) values('lisi');
commit;
id | name | 创建时间(事务ID) | 删除时间(事务ID) |
---|---|---|---|
1 | shenjian | 1 | undefinded |
2 | zhangsan | 1 | undefinded |
3 | lisi | 1 | undefinded |
对select 的影响:
innodb 只会去查找版本好小于或等于(早于)当前事务ID的数据行,这样可以确保事务读取的行,要么是在事务开始前已经存在的,要么是事务自身插入或者修改过的
行的删除版本要么未定义,要么大于当前事务版本号,这可以确保事务读取到的行,在事务开始之前未被删除.
只有1、2同时满足的记录,才能返回作为查询结果.
例2:delete操作
InnoDB会为删除的每一行保存当前系统的版本号(事务的ID)作为删除标识.
看下面的具体例子分析:
第二个事务,ID为2;
start transaction;
select * from tb; //(第一步操作:1)
select * from tb; //(第二部操作:2)
commit;
假设:在这个事务的的执行过程中到第一步操作:1 的时候。
又开启了一个新事务(ID 为3)向表中执行Insert 操作插入数据
start transaction;
insert into tb(name) values('wangwu') ;
commit;
此时的表中数据为:
id | name | 创建时间(事务ID) | 删除时间(事务ID) |
---|---|---|---|
1 | shenjian | 1 | undefinded |
2 | zhangsan | 1 | undefinded |
3 | lisi | 1 | undefinded |
4 | wangwu | 3 | undefinded |
然后刚才事务2,中的第二步:2 开始执行,引文id=4的数据的创建时间(事务ID为3),执行当前事务的ID为2,而InnoDB只会查找事务ID小于等于当前事务ID的数据行,所以id=4的数据行并不会在执行事务2中的第二步:2 中被检索出来,在事务2中的两条select 语句检索出来的数据都只会下表:
id | name | 创建时间(事务ID) | 删除时间(事务ID) |
---|---|---|---|
1 | shenjian | 1 | undefinded |
2 | zhangsan | 1 | undefinded |
3 | lisi | 1 | undefinded |
再假设:假设在执行事务ID为2的过程中,刚执行到了第一步:1,假设事务执行完事务3后,接着又执行了事务4;
事务4:
st art transaction;
delete from tb where id=1;
commit;
此时数据库中的表为:
id | name | 创建时间(事务ID) | 删除时间(事务ID) |
---|---|---|---|
1 | shenjian | 1 | 4 |
2 | zhangsan | 1 | undefinded |
3 | lisi | 1 | undefinded |
4 | wangwu | 3 | undefinded |
接着执行事务ID为2的第二步:2,根据select 检索条件可以知道,它会检索创建时间(创建事务的ID)小于当前事务ID的行和删除时间(删除事务的ID)大于当前事务的行,而id=4的行上面已经说过,而id=1的行由于删除时间(删除事务的ID)大于当前事务的ID,所以事务2的第二步:2 select * from tb 会把id=1的数据检索出来.所以,事务2中的两条select 语句检索出来的数据都如下:
id | name | 创建时间(事务ID) | 删除时间(事务ID) |
---|---|---|---|
1 | shenjian | 1 | 4 |
2 | zhangsan | 1 | undefinded |
3 | lisi | 1 | undefinded |
update:
InnoDB执行UPDATE,实际上是新插入了一行记录,并保存其创建时间为当前事务的ID,同时保存当前事务ID到要UPDATE的行的删除时间.
再再假设:
假设在执行完事务2的第一步:1 后又执行,其它用户执行了事务3,4,这时,又有一个用户对这张表执行了UPDATE操作:
第5个事务:
start transaction;
update tb set name='xxx' where id=2;
commit;
按照update的更新原则:会生成新的一行,并在原来要修改的列的删除时间列上添加本事务ID,得到表如下:
id | name | 创建时间(事务ID) | 删除时间(事务ID) |
---|---|---|---|
1 | shenjian | 1 | 4 |
2 | zhangsan | 1 | 5 |
3 | lisi | 1 | undefinded |
4 | wangwu | 3 | undefinded |
2 | xxx | 5 | undefinded |
继续执行事务2第二步:2,根据select 语句的检索条件(创建时间事务ID小于自己查询事务ID的,和删除时间事务ID大于自身的查询事务ID),得到下表:
id | name | 创建时间(事务ID) | 删除时间(事务ID) |
---|---|---|---|
1 | shenjian | 1 | 4 |
2 | zhangsan | 1 | 5 |
3 | lisi | 1 | undefinded |
并得不到上上个表的ID=4的第四行(因为创建事务ID=3 > 查询事务ID=2) 和第五行Update 事务创建的ID=2 的更新数据(因为 创建他的Update 事务ID=5 > 查询事务ID=2)
Mysql 中的MVCC原理,undo日志的依赖的更多相关文章
- MySQL中redo log、undo log、binlog关系以及区别
MySQL中redo log.undo log.binlog关系以及区别 本文转载自:MySQL中的重做日志(redo log),回滚日志(undo log),以及二进制日志(binlog)的简单总结 ...
- Mysql中主从复制的原理、配置过程以及实际案例
Mysql中主从复制的原理.配置过程以及实际案例1.什么是主从复制?原理:主从分离,什么意思呢?我们不妨画个图看看.如图1所示: 2.准备工作:预备两台服务器,我这里使用虚拟机安装了两个Centos6 ...
- MySQL中几种常见的日志
前言: 在 MySQL 系统中,有着诸多不同类型的日志.各种日志都有着自己的用途,通过分析日志,我们可以优化数据库性能,排除故障,甚至能够还原数据.这些不同类型的日志有助于我们更清晰的了解数据库,在日 ...
- MySQL中的事务原理和锁机制
本文主要总结 MySQL 事务几种隔离级别的实现和其中锁的使用情况. 在开始前先简单回顾事务几种隔离级别以及带来的问题. 四种隔离级别:读未提交.读已提交.可重复读.可串行化. 带来的问题:脏读.不可 ...
- 面试官:什么是MySQL 事务与 MVCC 原理?
作者:小林coding 图解计算机基础网站:https://xiaolincoding.com/ 大家好,我是小林. 之前写过一篇 MySQL 的 MVCC 的工作原理,最近有读者在网站上学习的时候, ...
- 说说MySQL中的Redo log Undo log都在干啥
在数据库系统中,既有存放数据的文件,也有存放日志的文件.日志在内存中也是有缓存Log buffer,也有磁盘文件log file,本文主要描述存放日志的文件. MySQL中的日志文件, ...
- MySql中innodb存储引擎事务日志详解
分析下MySql中innodb存储引擎是如何通过日志来实现事务的? Mysql会最大程度的使用缓存机制来提高数据库的访问效率,但是万一数据库发生断电,因为缓存的数据没有写入磁盘,导致缓存在内存中的数据 ...
- 【转】说说MySQL中的Redo log Undo log都在干啥
阅读目录(Content) 1 undo 1.1 undo是啥 1.2 undo参数 1.3 undo空间管理 2 redo 2.1 redo是啥 2.2 redo 参数 2.3 redo 空间管理 ...
- mysql中slow query log慢日志查询分析
在mysql中slow query log是一个非常重要的功能,我们可以开启mysql的slow query log功能,这样就可以分析每条sql执行的状态与性能从而进行优化了. 一.慢查询日志 配置 ...
随机推荐
- Cs231n课堂内容记录-Lecture1 导论
Lecture 1 视频网址:https://www.bilibili.com/video/av17204303/?p=2 https://zhuanlan.zhihu.com/p/21930884? ...
- Git&GitHub
Git是一个开源的分布式版本控制系统,可以有效.高速地处理从很小到非常大的项目版本管理. Git 是 Linus Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软 ...
- 删除window10没用的服务
最近学习了下resin,出了个问题,它默认端口是8080,跟Tomcat冲突了,我在使用的时候遇到了个奇怪的事情,resin4.0一直占用着我的8080端口,哪怕我用dos命令把它强制停止,不出五秒钟 ...
- CSS 浮动(float)与定位(position)
一.浮动 1.三个属性:left.right.none. 2.特点:容易造成父项塌陷,故在父项需要清除浮动 3.父项塌陷现象 4.父项塌陷解决方案(建议使用):清除浮动 .parent:after{ ...
- 部署tinyproxy代理服务
#安装依赖 yum install asciidoc #下载 wget https://github.com/tinyproxy/tinyproxy/releases/download/1.8.4/t ...
- Nginx使用教程(四):提高Nginx网络吞吐量之buffers优化
请求缓冲区在NGINX请求处理中起着重要作用. 在接收到请求时,NGINX将其写入这些缓冲区. 这些缓冲区中的数据可作为NGINX变量使用,例如$request_body. 如果缓冲区与请求大小相比较 ...
- (转)Spring Boot(十七):使用 Spring Boot 上传文件
http://www.ityouknow.com/springboot/2018/01/12/spring-boot-upload-file.html 上传文件是互联网中常常应用的场景之一,最典型的情 ...
- Shiro+JWT+Spring Boot Restful简易教程
序言 我也是半路出家的人,如果大家有什么好的意见或批评,请务必issue下. 项目地址:https://github.com/Smith-Cruise/Spring-Boot-Shiro . 如果想要 ...
- go第三方日志系统-seelog-使用文档
参考:https://godoc.org/github.com/cihub/seelog 导入方式: import "github.com/cihub/seelog" 包seelo ...
- zookeeper的原理,5分钟了解zookeeper
一 .Zookeeper功能简介 ZooKeeper 是一个开源的分布式协调服务,由雅虎创建,是 Google Chubby 的开源实现.分布式应用程序可以基于 ZooKeeper 实现诸如数据发布/ ...