Mysql可重复读原理

mysql可重复读现象及原理分析

InnoDB---可重复读隔离级别的底层实现原理

概念

可重复读的实现

Repeatable Read(可重复读):一个事务在执行过程中可以看到其他事务已经提交的新插入的记录(读已经提交的,其实是读早于本事务开始且已经提交的),但是不能看到其他事务对已有记录的更新(即晚于本事务开始的),并且,该事务不要求与其他事务是“可串行化”的。

这句话的核心,是“但是不能看到其他事务对已有记录的更新”,那么RR隔离级别是怎么保证这一点的呢?

实现原理

使用MVCC(多版本并发控制)。InnoDB为每行记录添加了一个版本号(系统版本号),每当修改数据时,版本号加一。
在读取事务开始时,系统会给事务一个当前版本号,事务会读取版本号<=当前版本号的数据,这时就算另一个事务插入一个数据,并立马提交,新插入这条数据的版本号会比读取事务的版本号高,因此读取事务读的数据还是不会变。

注意点

但是,当前事务想再写这行数据的话,还是以数据库提交的数据为准。并且会加行锁,其他的事务要再来修改的话,就得等到当前事务结束。

举例:

我们先看看现象,再分析原理。我的mysql版本是5.5。

下面是一张表,只有一条数据,并且我开启了事物

此时,另一个事物将record加1,因此我在开启一个命令行客户端,执行下面的命令:

成功加1之后,实际上,数据库中record肯定是2。

然后回到之前的客户端,再查一次:

没毛病,record还是1,果然是可重复读。有些人以为mysql的可重复读是通过行锁实现的,

从上面可以知道,肯定不是,如果是的话,第一次select * from test的时候,id=1的记录就会加行锁,我都加行锁了,我还没提交,另外的事物是怎么update成功的。

结论就是mysql使用的MVCC(多版本并发控制),MVCC详解可以看:https://blog.csdn.net/whoamiyang/article/details/51901888

我们继续,我之前的第一个事物还没提交,不过提交之前,我也想加1;

加完之后我再查一下,额,record是3,好像很奇怪,但也不奇怪。

其实,update test set record=record+1 where id=1;这条语句中,在加1之前,他知道自己等于2,然后2+1=3。

也就是说,update时读取数据是最新版本的数据,而select是到当前事物版本为止的数据。当更新成功之后,当前版本即为最新版本,再次select,读取的是最新的数据。

在这里讨论下乐观锁的必要性。下面是乐观锁的实现,实现乐观锁,我们一般会这么做

update test set record=record+1 where id=1 and record=1;

如果不用乐观锁,你用select读取到的值其实根本不准确。除非你开启悲观锁,像下面这样:

select * from test where id=1 for update;

这样可以读取到最新的内容,同时在你当前的事物提交之前,其他事物的update此条记录将会锁等待。

故事到此,还没有结束,此时我们开启事物三,也做加1操作看会发生什么。

结果是,锁等待超时,也就是说(事物一)在更新完后,会加行锁,这个应该比较好理解。事物中,刚开始查询的时候是不会加行锁的,但是当有更新操作之后,会加行锁,直到事物提交。

原文地址:https://www.cnblogs.com/fanguangdexiaoyuer/p/10759746.html

时间: 2024-07-30 01:47:47

Mysql可重复读原理的相关文章

MySQL可重复读采坑记录-对事务B进行更新时,事务A提交的更新会不会影响到事务B

之前线上出现数据重复插入的问题,通过对问题进行排查发现该问题和MySQL的默认隔离级别-Repeatable Read(可重读)有关系,可重复读确保同一事务的多个实例在并发读取数据时,会看到同样的数据行.现在通过实验,对问题进行下分析. 1.在终端A开启事务A,查询一下. START TRANSACTION; select spt.id,spt.audit_status,spt.is_deleted from stat_point_task spt limit 5; 结果如下: 2.在终端B开启

MySQL的可重复读级别能解决幻读吗

引言 之前在深入了解数据库理论的时候,了解到事物的不同隔离级别可能存在的问题.为了更好的理解所以在MySQL数据库中测试复现这些问题.关于脏读和不可重复读在相应的隔离级别下都很容易的复现了.但是对于幻读,我发现在可重复读的隔离级别下没有出现,当时想到难道是MySQL对幻读做了什么处理? 测试: 创建一张测试用的表dept: CREATE TABLE `dept` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(20) DEFAULT

面试官:MySQL的可重复读级别能解决幻读问题吗?

引言 之前在深入了解数据库理论的时候,了解到事务的不同隔离级别可能存在的问题.为了更好的理解所以在MySQL数据库中测试复现这些问题.关于脏读和不可重复读在相应的隔离级别下都很容易的复现了. 但是对于幻读,我发现在可重复读的隔离级别下没有出现,当时想到难道是MySQL对幻读做了什么处理? 测试: 创建一张测试用的表dept: CREATETABLE`dept`(`id`int(11)NOTNULLAUTO_INCREMENT,`name`varchar(20)DEFAULTNULL,PRIMAR

[MySQL]对于事务并发处理带来的问题,脏读、不可重复读、幻读的理解与数据库事务隔离级别 - 分析脏读 &amp; 不可重复读 &amp; 幻读

刚开始写博客.. 写的太low. 1.数据库的两种读,每种读读的数据版本不一样,所以也称为MVCC,即多版本并发控制 a) 快照读 select * from where xxx  这种形式的都是快照读. b) 当前读 update , insert ,delete ,select xx from xx for update ,  in share mode 都是当前读 当前读会等待,不会返回数据的历史版本 2.mvcc 的实现原理 mvcc是基于read view.活跃事务列表 做的,以后的文

Mysql事务,并发问题,锁机制-- 幻读、不可重复读(转)

1.什么是事务 事务是一条或多条数据库操作语句的组合,具备ACID,4个特点. 原子性:要不全部成功,要不全部撤销 隔离性:事务之间相互独立,互不干扰 一致性:数据库正确地改变状态后,数据库的一致性约束没有被破坏 持久性:事务的提交结果,将持久保存在数据库中 2.事务并发会产生什么问题 1)第一类丢失更新:在没有事务隔离的情况下,两个事务都同时更新一行数据,但是第二个事务却中途失败退出, 导致对数据的两个修改都失效了. 例如: 张三的工资为5000,事务A中获取工资为5000,事务B获取工资为5

mysql中事务隔离级别可重复读说明

mysql中InnoDB引擎默认为可重复读的(REPEATABLE READ).修改隔离级别的方法,你可以在my.inf文件的[mysqld]中配置: transaction-isolation = {READ-UNCOMMITTED | READ-COMMITTED | REPEATABLE-READ | SERIALIZABLE} 用户可以用SET TRANSACTION语句改变单个会话或者所有新进连接的隔离级别.它的语法如下: SET [SESSION | GLOBAL] TRANSACT

总是忘记的场景:MySQL InnoDB四个事务级别 与 脏读、不重复读、幻读

MySQL InnoDB事务隔离级别脏读.可重复读.幻读 MySQL InnoDB事务的隔离级别有四级,默认是“可重复读”(REPEATABLE READ). ·        未提交读(READUNCOMMITTED).另一个事务修改了数据,但尚未提交,而本事务中的SELECT会读到这些未被提交的数据(脏读). ·        提交读(READCOMMITTED).本事务读取到的是最新的数据(其他事务提交后的).问题是,在同一个事务里,前后两次相同的SELECT会读到不同的结果(不重复读).

MySQL选用可重复读之前一定要想到的事情

原文地址:http://blog.itpub.net/29254281/viewspace-1398273/ MySQL选用可重复读隔离级别之前一定要想到的事情.间隙锁 MySQL在使用之前有三个务必要知道..(随着了解的深入这个极有可能再增加..)1.DDL会引起metadata lock,导致请求连环阻塞,甚至是查询请求.http://blog.itpub.net/29254281/viewspace-1383193/ 2.MySQLDump和XtraBackup的flush table命令

MySQL InnoDB四个事务级别 与 脏读、不重复读、幻读

MySQL InnoDB事务隔离级别脏读.可重复读.幻读 希望通过本文,可以加深读者对ySQL InnoDB的四个事务隔离级别,以及脏读.不重复读.幻读的理解. MySQL InnoDB事务的隔离级别有四级,默认是"可重复读"(REPEATABLE READ). ·        未提交读(READUNCOMMITTED).另一个事务修改了数据,但尚未提交,而本事务中的SELECT会读到这些未被提交的数据(脏读). ·        提交读(READCOMMITTED).本事务读取到的