一 【背景】
   今天上午文能提笔安天下,武能上马定乾坤的登博给团队出了一道题目,谁先复现问题,奖励星巴克一杯。激起了一群忙碌的屌丝DBA的极大热情。问题是这样滴,如下图

登博提示了几个细节:
   1. code上的uk并未失效。
   2. rr隔离级别。
   3. 有并发线程的操作。
二 【原理分析】
1 事务隔离级别的基础知识:

  • 未提交读(Read Uncommitted):允许脏读,也就是可能读取到其他会话中未提交事务修改的数据。
  • 提交读(Read Committed):只能读取到已经提交的数据。Oracle等多数数据库默认都是该级别 (不重复读)。
  • 可重复读(Repeated Read):可重复读。在同一个事务内的查询都是事务开始时刻一致的,InnoDB默认级别。在SQL标准中,该隔离级别消除了不可重复读,但是还存在幻象读。
  • 串行读(Serializable):完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞。

这里重点说一下RR 模式:可重复读 是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另外一个事务也访问该同一数据。那么,在第一个事务中的两次读数据之间,即使第二个事务对数据进行修改,第一个事务两次读到的的数据是一样的。这样就发生了在一个事务内两次读到的数据是一样的,因此称为是可重复读。
2 MVCC 的读操作

   在MVCC并发控制中,读操作可以分成两类:快照读 (snapshot read)与当前读 (current read)。快照读,读取的是记录的可见版本 (有可能是历史版本),不用加锁。
当前读,读取的是记录的最新版本,并且,当前读返回的记录,都会加上锁,保证其他事务不会再并发修改这条记录。
快照读:简单的select操作,属于快照读,不加锁。
select * from table where ?;
当前读:特殊的读操作,插入/更新/删除操作,属于当前读,需要加锁。
select * from table where ? lock in share mode;
select * from table where ? for update;
insert into table values (…);
update table set ? where ?;
delete from table where ?;
所有以上的语句,都属于当前读,读取记录的最新版本。并且,读取之后,还需要保证其他并发事务不能修改当前记录,对读取记录加锁。其中,除了第一条语句,对读取记录加S锁 (共享锁)外,其他的操作,都加的是X锁 (排它锁)。
注意:insert操作可能会触发Unique Key的冲突检查,也会进行一个当前读。
 

三【解决.复现】
测试版本: 5.5.18 5.6.16 均可复现。
现在我们根据上述理论信息进行复现问题,具体的实现步骤如下:
注意 数据库的隔离级别为RR 

session 1 session 2
root@test 08:47:41>set global tx_isolation='REPEATABLE-READ';
Query OK, 0 rows affected (0.00 sec)
root@test 08:53:16>set autocommit=0;
Query OK, 0 rows affected (0.00 sec)
root@test 08:53:22>insert into yy values(1,20,13);
Query OK, 1 row affected (0.00 sec)
root@test 08:53:31>commit;
Query OK, 0 rows affected (0.00 sec)
root@test 08:53:39>select * from yy;
+----+------+------+
| id | code | val  |
+----+------+------+
|  1 |   20 |   13 |
+----+------+------+
1 row in set (0.00 sec)
 
  root@test 08:53:46>select * from yy;
+----+------+------+
| id | code | val  |
+----+------+------+
|  1 |   20 |   13 |
+----+------+------+
1 row in set (0.00 sec)
root@test 08:53:53>delete from yy where id=1;
Query OK, 1 row affected (0.00 sec)
root@test 08:53:59>commit;
root@test 08:54:10>insert into yy values(2,20,13);
Query OK, 1 row affected (5.59 sec)
root@test 08:54:23>select * from yy;
+----+------+------+
| id | code | val  |
+----+------+------+
|  1 |   20 |   13 |
|  2 |   20 |   13 |
+----+------+------+
2 rows in set (0.00 sec)
 

当session 2中将id=1 的删除之后,session1 进行insert操作时,触发unique key冲突检查,此时因为id=1 code=20的数据已经被物理删除了,MySQL 检查无冲突,进行insert insert into yy values(2,20,13); 便成功了。
四【结果展示】

五【参考资料】
 1 《MySQL 加锁分析
 2 《Innodb中的事务隔离级别和锁的关系

 
原文blog:

【MySQL】可重复读模式下 unique key失效案例的更多相关文章

  1. Mysql可重复读原理

    mysql可重复读现象及原理分析 InnoDB---可重复读隔离级别的底层实现原理 概念 可重复读的实现 Repeatable Read(可重复读):一个事务在执行过程中可以看到其他事务已经提交的新插 ...

  2. mysql 可重复读

    概念 Repeatable Read(可重复读):即:事务A在读到一条数据之后,此时事务B对该数据进行了修改并提交,那么事务A再读该数据,读到的还是原来的内容. 实现原理(MVCC [ 多版本并发控制 ...

  3. [PHP] swoole在daemonize模式下,chdir失效问题

    swoole version: 1.9.6 其实跟swoole的版本无关,因为原代码体系,fpm模式下,在启动的时候,是使用 chdir 函数改变了当前目录的,而其它代码在做类的自动加载的时候,都是写 ...

  4. MySQL 可重复读,差点就我背上了一个 P0 事故!

    小黑黑的碎碎念 哎,最近有点忙,备考复习不利,明天还要搬家,好难啊!! 本想着这周鸽了,但是想想还是不行,爬起来,更新一下,周更可不能断.偷懒一下,修改一下之前的一篇历史文章,重新发布一下. P0 事 ...

  5. MySQL Replication--开启GTID模式下匿名事务异常

    错误环境: OS: CentOS release 6.5 (Final) MySQL: MySQL 5.7.19 主从参数配置: master_info_repository = TABLE rela ...

  6. MySQL MGR 单主模式下master角色切换规则

    MGR单主模式,master节点可读可写,其余节点都是只读.当配置MGR为单主模式,非master节点自动开启super_read_only 当可读可写的节点异常宕机,会进行怎样的切换?在选择新的可写 ...

  7. mysql在命令行模式下创建数据库时要显式指定字符集

    create database db1 DEFAULT CHARACTER SET utf8 COLLATE utf8_chinese_ci;

  8. MySQL 在 Kubernetes IPVS 模式下引发的 TCP 超时问题

    文章转载自:https://mp.weixin.qq.com/s/XQ2SlCYxvXPY0rRRO-CURA

  9. 搞定面试官 - 你可以介绍一下在 MySQL 中,哪些情况下 索引会失效嘛?

    大家好,我是程序员啊粥,前边给大家分享了 *MySQL InnoDB 索引模型 在 MySQL InnoDB 中,为什么 delete 删除数据之后表数据文件大小没有变 如何计算一个索引的长度 如何查 ...

随机推荐

  1. Codeforces Round #390 (Div. 2) A

    One spring day on his way to university Lesha found an array A. Lesha likes to split arrays into sev ...

  2. ES6语言特性,如何在低版本浏览器运行它

    Introduction ECMAScript 6 于今年6月正式成为了标准,关于ES6,我们最大的疑虑可能是客户端浏览器还没有完全支持它,也就node.js用用. 有很多种手段可以解决这个问题,比如 ...

  3. 爬虫的两种解析方式 xpath和bs4

    1.xpath解析 from lxml import etree 两种方式使用:将html文档变成一个对象,然后调用对象的方法去查找指定的节点 (1)本地文件 tree = etree.parse(文 ...

  4. 【NumPy学习指南】day4 多维数组的切片和索引

    ndarray支持在多维数组上的切片操作.为了方便起见,我们可以用一个省略号(...)来 表示遍历剩下的维度. (1) 举例来说,我们先用arange函数创建一个数组并改变其维度,使之变成一个三维数组 ...

  5. 访问修饰符(C# 参考)

    第一篇 就抄写了一下下MSDN上面的东西练练手吧!!! 访问修饰符是一些关键字,用于指定声明的成员或类型的可访问性.             本节介绍四个访问修饰符: public protected ...

  6. UVA 1349 Optimal Bus Route Design (二分图最小权完美匹配)

    恰好属于一个圈,那等价与每个点有唯一的前驱和后继,这让人想到了二分图, 把一个点拆开,点的前驱作为S集和点的后继作为T集,然后连边,跑二分图最小权完美匹配. 写的费用流..最大权完美匹配KM算法没看懂 ...

  7. leetcode_1052. Grumpy Bookstore Owner

    1052. Grumpy Bookstore Owner https://leetcode.com/problems/grumpy-bookstore-owner/ 题意:每个时刻i会有custome ...

  8. js 前端不调接口直接下载图片

    // 下载图片 downPhoto (path) { this.downloadFiles(path) }, // 下载 downloadFiles (content) { console.log(c ...

  9. 复合词UVa10391(STL简单应用)

    一.题目 输入一系列由小写字母组成的单词.输入已按照字典序排序(这句话就是个陷阱),且不超过120000个.找出所有的复合词,即恰好由两个单词连接而成的单词. 二.解题思路 要么枚举两两拼接的情况,O ...

  10. vue watch 监听

    1.普通的watch data() { return { frontPoints: 0 } }, watch: { frontPoints(newValue, oldValue) { console. ...