文档章节

MySQL REPEATABLE-READ && 幻读

秋风醉了
 秋风醉了
发布于 2014/07/30 16:39
字数 1145
阅读 4.2K
收藏 7

3 月,跳不动了?>>>

MySQL REPEATABLE-READ && 幻读

关于mysql命令行中事务控制的语句见该文章

http://my.oschina.net/xinxingegeya/blog/296459

关于MVCC多版本控制

http://my.oschina.net/xinxingegeya/blog/208821

表结构

create table t1(
    a int primary key,
    b int not null    
)

 

REPEATABLE-READ可重复读(一)

这里打开两个mysql的命令行窗口,窗口A,即session1,窗口B,即session2。

session1

mysql> begin ;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from t1;
+----+------+
| a  | b    |
+----+------+
| 51 | 3000 |
| 52 | 3000 |
| 53 | 3000 |
| 54 | 3000 |
+----+------+
4 rows in set (0.00 sec)

以上sql只是显示的开启了事务,执行了sql查询。下面看session2的操作。

要注意这里的select操作是一般的快照读。根据MVCC多版本控制规则读取的数据行。

session2

mysql> begin ;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into t1 values (55, 3000);
Query OK, 1 row affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.03 sec)

mysql> select * from t1;
+----+------+
| a  | b    |
+----+------+
| 51 | 3000 |
| 52 | 3000 |
| 53 | 3000 |
| 54 | 3000 |
| 55 | 3000 |
+----+------+
5 rows in set (0.00 sec)

session2插入了一条数据,并显式的提交了事务。

session1

此时返回session1进行以下操作

mysql> select * from t1;
+----+------+
| a  | b    |
+----+------+
| 51 | 3000 |
| 52 | 3000 |
| 53 | 3000 |
| 54 | 3000 |
+----+------+
4 rows in set (0.00 sec)

此时,虽然在session2中插入了一条数据,并且提交了事务,但在session1中的查询和session1的上次查询还是同一个结果,这就是重复读。(也可以说是根据MVCC规则读取的数据行)。如果是在"READ-COMMITTED"级别下是可以读到a=55这条记录的(因为session2在刚才已经提交了事务)。

 

REPEATABLE-READ可重复读(二)

session1

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from t1 where a = 56;
+----+------+
| a  | b    |
+----+------+
| 56 | 7000 |
+----+------+
1 row in set (0.00 sec)

session1,开启了一个事务,查询a = 56 的记录。

session2 

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> update t1 set b = 8000 where a = 56;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from t1 where a = 56;
+----+------+
| a  | b    |
+----+------+
| 56 | 8000 |
+----+------+
1 row in set (0.00 sec)

mysql> commit
    -> ;
Query OK, 0 rows affected (0.04 sec)

session2开启了事务,更新a = 56 的记录,同时查询a = 56 的记录,可以看到在同一事务内重复读的效果。

session1

mysql> select * from t1 where a = 56;
+----+------+
| a  | b    |
+----+------+
| 56 | 7000 |
+----+------+
1 row in set (0.00 sec)

和上次查询结果一致,验证了重复读。还是要注意这里的select操作只是一般的快照读。其实不管session2 做什么操作,这里的快照读都是重复读的。

此时,如果session1提交该事务,重新开启事务,查询能查到session2中修改的结果

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from t1 where a = 56;
+----+------+
| a  | b    |
+----+------+
| 56 | 8000 |
+----+------+
1 row in set (0.00 sec)

注:以上的重复读,虽然在当前事务中真的是重复读的现象,但到底来说是通过MVCC多版本控制实现的可重复读。

 

REPEATABLE-READ与幻读

session1 

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from t1;
+----+------+
| a  | b    |
+----+------+
| 51 | 3000 |
| 52 | 3000 |
| 53 | 3000 |
| 54 | 3000 |
| 55 | 4000 |
| 56 | 8000 |
+----+------+
6 rows in set (0.00 sec)

开启事务,select操作为快照读。

session2

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from t1;
+----+------+
| a  | b    |
+----+------+
| 51 | 3000 |
| 52 | 3000 |
| 53 | 3000 |
| 54 | 3000 |
| 55 | 4000 |
| 56 | 8000 |
+----+------+
6 rows in set (0.00 sec)

mysql> insert into t1 values (57, 1000);
Query OK, 1 row affected (0.00 sec)

mysql> select * from t1;
+----+------+
| a  | b    |
+----+------+
| 51 | 3000 |
| 52 | 3000 |
| 53 | 3000 |
| 54 | 3000 |
| 55 | 4000 |
| 56 | 8000 |
| 57 | 1000 |
+----+------+
7 rows in set (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.11 sec)

在session2 中做了一系列的操作,插入insert,这里其实是当前读(写入)。然后提交事务。

session1 

mysql> update t1 set b = b+1000;
Query OK, 7 rows affected (0.00 sec)
Rows matched: 7  Changed: 7  Warnings: 0

mysql> select * from t1;
+----+------+
| a  | b    |
+----+------+
| 51 | 4000 |
| 52 | 4000 |
| 53 | 4000 |
| 54 | 4000 |
| 55 | 5000 |
| 56 | 9000 |
| 57 | 2000 |
+----+------+
7 rows in set (0.00 sec)

session1做更新操作,这里更新成功。如果session2 插入记录后,没有提交事务,这里更新是要阻塞的,因为session2 插入记录持有那条记录的X锁。

session1整个会话的sql

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from t1;
+----+------+
| a  | b    |
+----+------+
| 51 | 3000 |
| 52 | 3000 |
| 53 | 3000 |
| 54 | 3000 |
| 55 | 4000 |
| 56 | 8000 |
+----+------+
6 rows in set (0.00 sec)

mysql> select * from t1;
+----+------+
| a  | b    |
+----+------+
| 51 | 3000 |
| 52 | 3000 |
| 53 | 3000 |
| 54 | 3000 |
| 55 | 4000 |
| 56 | 8000 |
+----+------+
6 rows in set (0.00 sec)

mysql> update t1 set b = b+1000;
Query OK, 7 rows affected (0.00 sec)
Rows matched: 7  Changed: 7  Warnings: 0

mysql> select * from t1;
+----+------+
| a  | b    |
+----+------+
| 51 | 4000 |
| 52 | 4000 |
| 53 | 4000 |
| 54 | 4000 |
| 55 | 5000 |
| 56 | 9000 |
| 57 | 2000 |
+----+------+
7 rows in set (0.00 sec)

mysql>

可以看到多出了一行,这算是幻读吗?其实不是。这是根据MVCC的select规则读出来的数据

请详见http://my.oschina.net/xinxingegeya/blog/505675

 

总结:

REPEATABLE READ:在mysql中,不会出现幻读。mysql的实现和标准定义的RR隔离级别有差别。

==========END==========

© 著作权归作者所有

秋风醉了
粉丝 253
博文 532
码字总数 405557
作品 0
朝阳
程序员
私信 提问
加载中

评论(10)

Ambitor
Ambitor
而且这个时候 当你session1再update的时候,受影响的行时7行,然后你再select 一遍 这个时候你会在session1中查出7条记录。 这个应该是对MVCC可见性的一种特殊处理了,但是 可以验证的是,session1的版本可见性是永远看不到session2的。 Trx read view will not see trx with id >= session2, sees < session2
Ambitor
Ambitor

引用来自“Ambitor”的评论

楼主是不是代码贴反了?一才是幻读 二是重复读?

引用来自“xxggy”的评论

REPEATABLE-READ可重复读(一)
REPEATABLE-READ可重复读(二)
都是 REPEATABLE-READ 隔离级别体现的可重复读特性。

引用来自“Ambitor”的评论

哈哈,这个地方有点模棱两可。一般可重复读是指的update 操作,而insert delete 操作 被称为幻读。

引用来自“xxggy”的评论

一般可重复读是指的update 操作,而insert delete 操作 被称为幻读 -----不太明白什么意思。。

可重复读的不就是 说在RR隔离级别下 在同一个事务内,前后select 操作读到的结果都是一致的 。

而幻读的例子我在 REPEATABLE-READ与幻读 这个标题下说了,我觉得可以认为是幻读也可以认为不是幻读。首先他具有幻读的特征表现,但在底层本质 是MVCC 多版本控制的结果。不知道你赞不赞同~~
我感觉你幻读示例的原因不是因为MVCC多版本控制的版本可见性。因为你的session1的可见性是看不到session2的版本,你用show engine innodb status 就可以打印看到,那为什么session1的修改可以改到session2的那条insert数据呢,首先我觉得对数据page的修改肯定都是在当前最新版本的,也就是不可能去修改历史undo版本,然后这个数据page其实在被session2的事务已经修改了,所以session1再去作用的时候,那条新insert的数据也被修改,其实这个就是幻读,只有在session1读的时候就加上share mode 才能避免吧。
秋风醉了
秋风醉了 博主

引用来自“Ambitor”的评论

楼主是不是代码贴反了?一才是幻读 二是重复读?

引用来自“xxggy”的评论

REPEATABLE-READ可重复读(一)
REPEATABLE-READ可重复读(二)
都是 REPEATABLE-READ 隔离级别体现的可重复读特性。

引用来自“Ambitor”的评论

哈哈,这个地方有点模棱两可。一般可重复读是指的update 操作,而insert delete 操作 被称为幻读。
一般可重复读是指的update 操作,而insert delete 操作 被称为幻读 -----不太明白什么意思。。

可重复读的不就是 说在RR隔离级别下 在同一个事务内,前后select 操作读到的结果都是一致的 。

而幻读的例子我在 REPEATABLE-READ与幻读 这个标题下说了,我觉得可以认为是幻读也可以认为不是幻读。首先他具有幻读的特征表现,但在底层本质 是MVCC 多版本控制的结果。不知道你赞不赞同~~
秋风醉了
秋风醉了 博主

引用来自“Ambitor”的评论

还有,我发现一个问题,当你执行begin;或者START TRANSACTION开启事务后,这个时候其实并不会生成新的txId,应该也不会产生read view,而只有当你真正执行第一个sql的时候 才会生成一个新的txId----------------------------------------------------------这个 也可以通过 show engine innodb status 验证。。
这个赞同。抽空我会自己验证一下~
Ambitor
Ambitor
还有,我发现一个问题,当你执行begin;或者START TRANSACTION开启事务后,这个时候其实并不会生成新的txId,应该也不会产生read view,而只有当你真正执行第一个sql的时候 才会生成一个新的txId----------------------------------------------------------这个 也可以通过 show engine innodb status 验证。。
Ambitor
Ambitor
还有,我发现一个问题,当你执行begin;或者START TRANSACTION开启事务后,这个时候其实并不会生成新的txId,应该也不会产生read view,而只有当你真正执行第一个sql的时候 才会生成一个新的txId, 所以如果你是事务A 先begin了 但是没有执行sql,然后切到事务B去begin、insert、commit 执行完 这个时候你再切换到A来执行select 就会发现 其实事务A是可以看到B Insert的那条数据!
Ambitor
Ambitor

引用来自“Ambitor”的评论

楼主是不是代码贴反了?一才是幻读 二是重复读?

引用来自“xxggy”的评论

REPEATABLE-READ可重复读(一)
REPEATABLE-READ可重复读(二)
都是 REPEATABLE-READ 隔离级别体现的可重复读特性。
哈哈,这个地方有点模棱两可。一般可重复读是指的update 操作,而insert delete 操作 被称为幻读。
秋风醉了
秋风醉了 博主

引用来自“Ambitor”的评论

楼主是不是代码贴反了?一才是幻读 二是重复读?
REPEATABLE-READ可重复读(一)
REPEATABLE-READ可重复读(二)
都是 REPEATABLE-READ 隔离级别体现的可重复读特性。
秋风醉了
秋风醉了 博主

引用来自“Ambitor”的评论

楼主是不是代码贴反了?一才是幻读 二是重复读?
哪个 一,哪个 二?
Ambitor
Ambitor
楼主是不是代码贴反了?一才是幻读 二是重复读?
MySQL · 源码分析 · InnoDB Repeatable Read隔离级别之大不同

开始介绍之前,先让我们了解一些基本概念。ANSI SQL STANDARD定义了4类隔离级别(READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ, SERIALIZABLE),包括了一些具体规则,用来限定事务内外...

阿里云RDS-数据库内核组
2017/06/08
0
0
mysql乱七八糟的可重复读隔离级别实现

mysql的隔离级别并非是按照标准实现的,作为从pg切过来的程序员还真是不太适应,这篇文章讨论mysql隔离级别实现的,希望对大家能有帮助。 什么是事务 事务是数据库一组读写操作的集合,事务具...

徐文韬
2017/09/11
0
0
MySQl事务隔离级别(命令及简单理解)

1.查看当前会话隔离级别 select @@tx_isolation; 2.查看系统当前隔离级别 select @@global.tx_isolation; 3.设置当前会话隔离级别 set session transaction isolatin level repeatable read...

凡尘网络
2015/12/15
123
0
【20180613】MySQL innodb 引擎如何解决幻读

MySQL innodb 引擎如何解决幻度 MySQL innodb 引擎事务的隔离级别有四种,默认是可重复读(REPEATABLE READ) 未提交读(READ UNCOMMITTED)。俩个不同session,一个session正在显式的开启事务进...

liuhuang9496
2018/06/13
0
0
数据库事务隔离级别(面试题 )

今天请了一天假去卓望公司面试,被问到数据库隔离机制的问题,真的没准备,平时的工作用到的也不多,数据库默认机制是啥也没怎么关心,回来看了点资料,打开mysql测试了一下,终于清楚了!总结...

在水一方发盐人
2016/11/11
660
0

没有更多内容

加载失败,请刷新页面

加载更多

ftp杂记

1. 配置文件 有些版本的配置文件在/etc/vsftpd.conf,有些在 /etc/vsftpd/vsftpd.conf; 这样需要手动查找配置文件vsftpd.conf ,退回根目录,使用查找命令: find / -name 'vsftpd.conf' 2.指定f...

流光韶逝
13分钟前
10
0
Linux安装rabbitMQ

官网 : http://www.rabbitmq.com/install-rpm.html

那个猩猩很亮
19分钟前
7
0
linux定时任务crond export变量问题群友案例

linux定时任务crond export变量问题群友案例 1)我写了一个重启resin的脚本,由于业务原因,需要定时在某一个时间重启下resin服务器,于是就在 crontab里配置了如下内容: 50 17 * * 1-5 ro...

chen虎
23分钟前
12
0
iWork文档批量转换工具Docxtor for Mac如何使用?

你有大量的iWork™文件想与同事或朋友分享,但是你的朋友没有Mac并且无法打开iWork™文档?别担心,你可以将iWork™文档导出为Microsoft Office™!今天小编要给大家分享的是iWork文档批量转...

mac小叮当
29分钟前
17
0
python笔记:python实现带附件的邮件自动发送

目标:设置邮件自动发送 本文按照《对比Excel,轻松学习Python数据分析》中第14章自动发送电子邮件实例编写,试验成功,分享代码给大家 #!/usr/bin/env python# coding: utf-8# In[2]:...

小玲_001
31分钟前
15
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部