RR隔离级别下通过next-key locks 避免幻影读
---恢复内容开始---
mysql innodb目前使用范围最广的两种隔离级别为RC和RR,RR修复了RC中所存在的不可重复读
READ COMMITED
不可重复读
在同一事务中两次查看的结果集不同,如下session1的查看结果集受session2提交的事物影响
05:47:35[test](;)> select @@tx_isolation;
+----------------+
| @@tx_isolation |
+----------------+
| READ-COMMITTED |
+----------------+ session1
03:28:11[test](;)> begin;
Query OK, 0 rows affected (0.00 sec) 03:28:21[test](;)> select * from t1;
Empty set (0.01 sec)
session2
03:28:27[test](;)> insert into t1 values(1,1,1,1,1);
Query OK, 1 row affected (0.00 sec)
03:29:25[test](;)> select * from t1;
+----+------+------+------+------+
| id | col1 | col2 | col3 | col4 |
+----+------+------+------+------+
| 1 | 1 | 1 | 1 | 1 |
+----+------+------+------+------+
1 row in set (0.00 sec)
幻影读(Phantom Rows)
什么是幻影读
同一事务保证了一致性读后,查询时对提交的事务是不可见的,但是变更的时候是可见的,所以就有可能引发幻影读
为什么会导致幻影读
对于update或delete操作(可以使用SELECT with FOR UPDATE or LOCK IN SHARE MODE来进行模拟),innodb只加记录锁(满足条件索引记录)而不是gap锁,gap锁只用于外键约束和duplicate key的检查,所以允许另一事务在锁定的记录旁边自由插入新记录
如col2上有索引,在满足col2>5的条件索引上加索引(对于RC,只在col2为10的索引记录上加X lock),所以在另一会话总插入col2 为非10的记录则会成功
set tx_isolation='read-committed' ;
session 1
07:46:16[test](;)> begin;
Query OK, 0 rows affected (0.00 sec) 07:46:20[test](;)> select * from t1 where col2>5 for update;
+----+------+------+------+------+
| id | col1 | col2 | col3 | col4 |
+----+------+------+------+------+
| 2 | 2 | 10 | 2 | 2 |
+----+------+------+------+------+
1 row in set (0.00 sec)
07:44:48[test](;)> begin;
Query OK, 0 rows affected (0.00 sec) 07:46:36[test](;)> insert into t1 values(3,3,6,3,3);
Query OK, 1 row affected (0.00 sec) 07:46:38[test](;)> commit;
Query OK, 0 rows affected (0.10 sec)
07:46:31[test](;)> select * from t1 where col2>5;
+----+------+------+------+------+
| id | col1 | col2 | col3 | col4 |
+----+------+------+------+------+
| 3 | 3 | 6 | 3 | 3 |
| 2 | 2 | 10 | 2 | 2 |
+----+------+------+------+------+
2 rows in set (0.00 sec)
若col2上无索引,也会是同样的结果现象,如果条件字段上无索引,innodb会先将所有行都加上锁,然后返回给server层根据条件筛选,满足条件则释放行锁,不满足条件则不释放
REPEATABLE READ
如何实现可重复读
事物开始时记录当前的快照版本,事务期间读取的都是事务开始时的快照版本
如何避免幻影读
通过 next-key lock 锁机制,是由index-row lock和gap lock组合成的
如,条件为col2>5,会在区间上[1,5],(5,正无穷)加index-row lock
08:30:02[test](;)> set tx_isolation='repeatable-read' ;
08:30:49[test](;)> select * from t1;
+----+------+------+------+------+
| id | col1 | col2 | col3 | col4 |
+----+------+------+------+------+
| 1 | 1 | 1 | 1 | 1 |
| 2 | 2 | 10 | 2 | 10 |
+----+------+------+------+------+
2 rows in set (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
08:31:02[test](;)> begin;
Query OK, 0 rows affected (0.00 sec) 08:31:05[test](;)> select * from t1 where col2>5 for update;
+----+------+------+------+------+
| id | col1 | col2 | col3 | col4 |
+----+------+------+------+------+
| 2 | 2 | 10 | 2 | 10 |
+----+------+------+------+------+
1 row in set (0.00 sec)
08:30:51[test](;)> begin;
Query OK, 0 rows affected (0.00 sec) 08:32:11[test](;)> insert into t1 values(3,3,6,3,6);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
---恢复内容结束---
mysql innodb目前使用范围最广的两种隔离级别为RC和RR,RR修复了RC中所存在的不可重复读
READ COMMITED
不可重复读
在同一事务中两次查看的结果集不同,如下session1的查看结果集受session2提交的事物影响
05:47:35[test](;)> select @@tx_isolation;
+----------------+
| @@tx_isolation |
+----------------+
| READ-COMMITTED |
+----------------+ session1
03:28:11[test](;)> begin;
Query OK, 0 rows affected (0.00 sec) 03:28:21[test](;)> select * from t1;
Empty set (0.01 sec)
session2
03:28:27[test](;)> insert into t1 values(1,1,1,1,1);
Query OK, 1 row affected (0.00 sec)
03:29:25[test](;)> select * from t1;
+----+------+------+------+------+
| id | col1 | col2 | col3 | col4 |
+----+------+------+------+------+
| 1 | 1 | 1 | 1 | 1 |
+----+------+------+------+------+
1 row in set (0.00 sec)
幻影读(Phantom Rows)
什么是幻影读
同一事务保证了一致性读后,查询时对提交的事务是不可见的,但是变更的时候是可见的,所以就有可能引发幻影读
为什么会导致幻影读
对于update或delete操作(可以使用SELECT with FOR UPDATE or LOCK IN SHARE MODE来进行模拟),innodb只加记录锁(满足条件索引记录)而不是gap锁,gap锁只用于外键约束和duplicate key的检查,所以允许另一事务在锁定的记录旁边自由插入新记录
如col2上有索引,在满足col2>5的条件索引上加索引(对于RC,只在col2为10的索引记录上加X lock),所以在另一会话总插入col2 为非10的记录则会成功
set tx_isolation='read-committed' ;
session 1
07:46:16[test](;)> begin;
Query OK, 0 rows affected (0.00 sec) 07:46:20[test](;)> select * from t1 where col2>5 for update;
+----+------+------+------+------+
| id | col1 | col2 | col3 | col4 |
+----+------+------+------+------+
| 2 | 2 | 10 | 2 | 2 |
+----+------+------+------+------+
1 row in set (0.00 sec)
07:44:48[test](;)> begin;
Query OK, 0 rows affected (0.00 sec) 07:46:36[test](;)> insert into t1 values(3,3,6,3,3);
Query OK, 1 row affected (0.00 sec) 07:46:38[test](;)> commit;
Query OK, 0 rows affected (0.10 sec)
07:46:31[test](;)> select * from t1 where col2>5;
+----+------+------+------+------+
| id | col1 | col2 | col3 | col4 |
+----+------+------+------+------+
| 3 | 3 | 6 | 3 | 3 |
| 2 | 2 | 10 | 2 | 2 |
+----+------+------+------+------+
2 rows in set (0.00 sec)
若col2上无索引,也会是同样的结果现象,如果条件字段上无索引,innodb会先将所有行都加上锁,然后返回给server层根据条件筛选,满足条件则释放行锁,不满足条件则不释放
REPEATABLE READ
如何实现可重复读
事物开始时记录当前的快照版本,事务期间读取的都是事务开始时的快照版本
如何避免幻影读
通过 next-key lock 锁机制,是由index-row lock和gap lock组合成的
如,条件为col2>5,会在区间上[1,5],(5,正无穷)加index-row lock
08:30:02[test](;)> set tx_isolation='repeatable-read' ;
08:30:49[test](;)> select * from t1;
+----+------+------+------+------+
| id | col1 | col2 | col3 | col4 |
+----+------+------+------+------+
| 1 | 1 | 1 | 1 | 1 |
| 2 | 2 | 10 | 2 | 10 |
+----+------+------+------+------+
2 rows in set (0.00 sec)
Query OK, 0 rows affected (0.00 sec)
08:31:02[test](;)> begin;
Query OK, 0 rows affected (0.00 sec) 08:31:05[test](;)> select * from t1 where col2>5 for update;
+----+------+------+------+------+
| id | col1 | col2 | col3 | col4 |
+----+------+------+------+------+
| 2 | 2 | 10 | 2 | 10 |
+----+------+------+------+------+
1 row in set (0.00 sec)
08:30:51[test](;)> begin;
Query OK, 0 rows affected (0.00 sec) 08:32:11[test](;)> insert into t1 values(3,3,6,3,6);
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
RR隔离级别下通过next-key locks 避免幻影读的更多相关文章
- InnoDB MVCC RR隔离级别下的数据可见性总结
一.背景 熟悉数据库隔离级别的人都知道,在RR(可重复读)隔离级别下,无论何时多次执行相同的SELECT快照读语句,得到的结果集都是完全一样的,即便两次SELECT语句执行期间,其他事务已经改变了该查 ...
- [原创]MySQL RR隔离级别下begin或start transaction开启事务后的可重复读?
Server version: 5.6.21-log MySQL Community Server (GPL) 前提提要: 我们知道MySQL的RR(repeatable read)隔 ...
- MySQL Transaction--RR事务隔离级别下加锁测试
============================================================================== 按照非索引列更新 在可重复读的事务隔离级别 ...
- Mysql 间隙锁原理,以及Repeatable Read隔离级别下可以防止幻读原理(百度)
Mysql知识实在太丰富了,前几天百度的面试官问我MySql在Repeatable Read下面是否会有幻读出现,我说按照事务的特性当然会有, 但是面试官却说 Mysql 在Repeatable Re ...
- MySQL Transaction--RC事务隔离级别下加锁测试
==============================================================================非索引列更新 在读提交的事务隔离级别下,在非 ...
- Innodb 中 RR 隔离级别能否防止幻读?
问题引出 我之前的一篇博客 数据库并发不一致分析 有提到过事务隔离级别以及相应加锁方式.能够解决的并发问题. 标准情况下,在 RR(Repeatable Read) 隔离级别下能解决不可重复读(当行修 ...
- InnoDB在MySQL默认隔离级别下解决幻读
1.结论 在RR的隔离级别下,Innodb使用MVVC和next-key locks解决幻读,MVVC解决的是普通读(快照读)的幻读,next-key locks解决的是当前读情况下的幻读. 2.幻读 ...
- 浅析SQL Server在可序列化隔离级别下,防止幻读的范围锁的锁定问题
本文出处:http://www.cnblogs.com/wy123/p/7501261.html (保留出处并非什么原创作品权利,本人拙作还远远达不到,仅仅是为了链接到原文,因为后续对可能存在的一些错 ...
- MySQL--REPEATABLE-READ隔离级别下读取到的“重复数据”
在MySQL中,使用MVCC来实现REPEATABLE-READ隔离级别,由于SELECT操作不会对数据加锁,其他回话可以修改当前回话所读取过的数据而不会被阻塞,因此读写不冲突. 在MVCC并发控制中 ...
随机推荐
- AJAX的JSON方式传回方法
AJAX返回数据的类型有两种,一种是TEXT类型,一种是JSON类型. 使用TEXT类型,访问数据库后将结果拼接成字符串,返回时在拆分成数组使用. JSON直接将结果转成JSON数据,返回时直接使用. ...
- idea npm 调试报错解决办法
1.用egg框架的开发时候,egg 提供本地开发和调试.点击idea 的debug 按钮时候报如下错误: Please specify npm or yarn package: cannot find ...
- SQL 时间日期函数
1.获取当前日期GetDate getdate()函数以datetime数据类型的格式返回当前SQLServer服务器所在计算机的日期和时间.其语法格式为getdate().返回值舍入到最近的秒小数部 ...
- POJ 2831 Can We Build This One?
Time Limit: 5000MS Memory Limit: 65536K Total Submissions: 1728 Accepted: 643 Case Time Limit: 2 ...
- python之数据类型补充
1. capitalize (首字母大写) 例题: s = "alex wusir" s1 = s.capitalize() # 格式 print(s1) ''' 输出结果 Ale ...
- Spring启动流程—源码解读
https://blog.csdn.net/yangliuhbhd/article/details/80790761 Spring的AbstractApplicationContext的refresh ...
- iCheck获取单选和复选框的值和文本
//获取单选和复选框的值//parameters.type:"radio","checkbox"//parameters.name:input-name//pa ...
- python-DB模块
基于python的接口测试框架设计 连接数据库 首先是连接数据库的操作,最好是单独写在一个模块里, 然后便于方便的调用,基于把connection连接放在__init__()方法里 然后分别定义D ...
- swift中使用sqlite3
import Foundation /** 1. 打开数据库 2. 如果没有数据表,需要首先创表 3. 数据操作 */ class SQLite { var db: COpaquePointer = ...
- sass --watch 失败bug
NameError: uninitialized constant Sass::Plugin::Compiler::SassListen 网上说法是sass v3.2.10有bug 但是我版本3.5. ...