MySQL在RR隔离级别下的unique失效和死锁模拟
今天在测试MySQL事务隔离级别的时候,发现了一个有趣的问题,也参考了杨一之前总结的一篇。http://blog.itpub.net/22664653/viewspace-1612574/
问题的背景是在MySQL隔离级别为RR(Repeatable Read)时,唯一性约束没有失效,多并发的场景下能够复现出下面的问题。
这样一个看起来不可能的事情,能否复现呢。
我都这么问了,潜台词就是可以,要不今天的笔记就一个问题就结束了。
为了模拟这个问题,我们打开两个会话窗口,来模拟一下这个问题。
mysql> create table test3(id1 int primary key,id2 int unique,id3 int); Query OK, 0 rows affected (0.01 sec) #会话1 set autocommit=0; mysql> insert into test3 values(1,20170831,1); Query OK, 1 row affected (0.00 sec) commit;
#会话2
这个时候充分利用了MVCC的特性,这是一个快照读。
mysql> select *from test3;
+-----+----------+------+
| id1 | id2 | id3 |
+-----+----------+------+
| 1 | 20170831 | 1 |
+-----+----------+------+
1 row in set (0.00 sec)
会话1插入了一条数据,我们在会话2中删除。 mysql> delete from test3 where id1=1; Query OK, 1 row affected (0.01 sec) mysql> commit; Query OK, 0 rows affected (0.00 sec) 提交之后,会话2中就修改完毕了。 #会话1
这个时候根据MVCC的特点,会话2中已经删除了id1=1的记录。所以主键列相关数据是插入不了了,那么唯一性索引呢。根据MVCC的特点,能够保证重复读的特点,读到的数据还是不变。
mysql> select *from test3;
+-----+----------+------+
| id1 | id2 | id3 |
+-----+----------+------+
| 1 | 20170831 | 1 |
+-----+----------+------+
1 row in set (0.00 sec)
现在的关键就来了,我们插入一条数据,主键不冲突,唯一性索引冲突,看看是否能够插入成功。
mysql> insert into test3 values(2,20170831,2); Query OK, 1 row affected (0.00 sec)
魔性的一幕上演了。
mysql> select *from test3; +-----+----------+------+ | id1 | id2 | id3 | +-----+----------+------+ | 1 | 20170831 | 1 | | 2 | 20170831 | 2 | +-----+----------+------+ 2 rows in set (0.00 sec) 当然到了这里,我们继续玩一玩,常规来说,插入主键列冲突数据可能是行不通的,比如id1=1,id2=20170831,id3=1,客户端很快会反馈失败。但是在这里做唯一性校验时,因为id1=1的数据已经被物理删除了。
mysql> insert into test3 values(1,20170831,1); ERROR 1062 (23000): Duplicate entry '20170831' for key 'id2'
我们就来继续模拟个死锁吧。
会话2:
这个步骤是做一次数据清理,where条件中是根据主键来查找删除。
mysql> delete from test3 where id1=1; Query OK, 0 rows affected (0.00 sec)
会话1:
mysql> insert into test3 values(1,20170831,1);
这个时候会话会被阻塞
会话2:
这个时候在会话2继续插入这个值,就会报出死锁问题。
mysql> insert into test3 values(1,20170831,1); ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
--产生死锁
会话1:
这个时候死锁有了,事务也自动回滚了。再次插入违反约束的数据,就不行了。
mysql> insert into test3 values(1,20170831,1); ERROR 1062 (23000): Duplicate entry '20170831' for key 'id2'
我们来看看在上面的测试过程中,关于死锁的日志: 2017-08-28T07:27:48.329631Z 14140 [Note] InnoDB: Transactions deadlock detected, dumping detailed information. 2017-08-28T07:27:48.329740Z 14140 [Note] InnoDB: *** (1) TRANSACTION: TRANSACTION 31790, ACTIVE 315 sec inserting mysql tables in use 1, locked 1 LOCK WAIT 5 lock struct(s), heap size 1136, 5 row lock(s), undo log entries 1 MySQL thread id 14138, OS thread handle 139809903986432, query id 108686 localhost root update insert into test3 values(1,20170831,1) 2017-08-28T07:27:48.329801Z 14140 [Note] InnoDB: *** (1) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 36 page no 3 n bits 72 index PRIMARY of table `test`.`test3` trx id 31790 lock mode S waiting Record lock, heap no 2 PHYSICAL RECORD: n_fields 5; compact format; info bits 0 0: len 4; hex 80000001; asc ;; 1: len 6; hex 000000007c2f; asc |/;; 2: len 7; hex 33000001ac2f63; asc 3 /c;; 3: len 4; hex 8133c84f; asc 3 O;; 4: len 4; hex 80000001; asc ;; 2017-08-28T07:27:48.330040Z 14140 [Note] InnoDB: *** (2) TRANSACTION: TRANSACTION 31791, ACTIVE 51 sec inserting mysql tables in use 1, locked 1 5 lock struct(s), heap size 1136, 4 row lock(s), undo log entries 1 MySQL thread id 14140, OS thread handle 139809903720192, query id 108687 localhost root update insert into test3 values(1,20170831,1) 2017-08-28T07:27:48.330084Z 14140 [Note] InnoDB: *** (2) HOLDS THE LOCK(S): RECORD LOCKS space id 36 page no 3 n bits 72 index PRIMARY of table `test`.`test3` trx id 31791 lock_mode X locks rec but not gap Record lock, heap no 2 PHYSICAL RECORD: n_fields 5; compact format; info bits 0 0: len 4; hex 80000001; asc ;; 1: len 6; hex 000000007c2f; asc |/;; 2: len 7; hex 33000001ac2f63; asc 3 /c;; 3: len 4; hex 8133c84f; asc 3 O;; 4: len 4; hex 80000001; asc ;; 2017-08-28T07:27:48.330342Z 14140 [Note] InnoDB: *** (2) WAITING FOR THIS LOCK TO BE GRANTED: RECORD LOCKS space id 36 page no 4 n bits 72 index id2 of table `test`.`test3` trx id 31791 lock mode S waiting Record lock, heap no 3 PHYSICAL RECORD: n_fields 2; compact format; info bits 0 0: len 4; hex 8133c84f; asc 3 O;; 1: len 4; hex 80000002; asc ;; 2017-08-28T07:27:48.330470Z 14140 [Note] InnoDB: *** WE ROLL BACK TRANSACTION (2)
这里会充分把x,s锁,细粒度锁的知识联系起来,搞明白又进步了一大截。
会话1:
最后,我们提交一下事务,再次查看数据,一切又恢复了平静。
mysql> commit; Query OK, 0 rows affected (0.00 sec)
mysql> select *from test3; +-----+----------+------+ | id1 | id2 | id3 | +-----+----------+------+ | 2 | 20170831 | 2 | +-----+----------+------+ 1 row in set (0.00 sec)
- 10g,11g中数据库静默安装中的细小差别(r6笔记第85天)
- SDP(8):文本式数据库-MongoDB-Scala基本操作
- SDP(7):Cassandra- Cassandra-Engine:Streaming
- TensorFlow实现神经网络入门篇
- 27.反射,类加载器,设计模式,jdk新特性
- SDP(6):分布式数据库运算环境- Cassandra-Engine
- 配置dg broker的问题分析及修复(r6笔记第84天)
- SDP(5):ScalikeJDBC- JDBC-Engine:Streaming
- SDP(4):ScalikeJDBC- JDBC-Engine:Updating
- SDP(3):ScalikeJDBC- JDBC-Engine:Fetching
- SDP(2):ScalikeJDBC-Connection Pool Configuration
- 使用外部表关联MySQL数据到Oracle(r6笔记第100天)
- 使用selenium模块模拟浏览器爬去网页,并进行点击定位内容笔记
- python 报错'gbk' codec can't encode character 'ue5d1' in position 0:
- MySQL 教程
- MySQL 安装
- MySQL 管理与配置
- MySQL PHP 语法
- MySQL 连接
- MySQL 创建数据库
- MySQL 删除数据库
- MySQL 选择数据库
- MySQL 数据类型
- MySQL 创建数据表
- MySQL 删除数据表
- MySQL 插入数据
- MySQL 查询数据
- MySQL where 子句
- MySQL UPDATE 查询
- MySQL DELETE 语句
- MySQL LIKE 子句
- mysql order by
- Mysql Join的使用
- MySQL NULL 值处理
- MySQL 正则表达式
- MySQL 事务
- MySQL ALTER命令
- MySQL 索引
- MySQL 临时表
- MySQL 复制表
- 查看MySQL 元数据
- MySQL 序列 AUTO_INCREMENT
- MySQL 处理重复数据
- MySQL 及 SQL 注入
- MySQL 导出数据
- MySQL 导入数据
- MYSQL 函数大全
- MySQL Group By 实例讲解
- MySQL Max()函数实例讲解
- mysql count函数实例
- MYSQL UNION和UNION ALL实例
- MySQL IN 用法
- MySQL between and 实例讲解
- Java——Stream数据流
- JavaWeb——MyBatis框架之连接池原理、MyBatis事务提交设置、动态SQL语法总结
- 8种ETL算法归纳总结,看完这些你就全明白了
- JavaWeb——Maven基础之详细总结,从零开始搭建Maven工程,包含一些常见的坑org.eclipse.jdt.internal.compiler.classfmt.ClassFormatEx
- JavaWeb——Redis数据库之Jedis操作5种类型数据的使用总结与前端Ajax获取Redis缓存数据的案例实战(结合了MySQL数据库)
- Java——数据库编程JDBC之快速入门吐血总结及各关键对象详解(提供了JDBCUtils工具类)
- MySQL数据库——事务的操作(开启、回滚、提交)、特征、隔离级别基础总结
- MySQL数据库——数据库的设计(多表之间的关系与三大范式)与备份还原
- JavaWeb——JSP入门学习(JSP基本概念、JSP脚本、JSP内置对象)
- MySQL数据库——数据库CRUD之基本DML增删改表操作及DQL查表操作
- JavaWeb——AJAX异步技术实现方式与案例实战(原生的JS方式、使用JQuery方式)
- JavaWeb——一文带你入门Servlet(生命周期、注解配置方法、IDEA与tomcat的相关配置)
- JavaWeb——JQuery之基础案例实战(实现表格隔行换色、实现全选全不选、QQ表情选择、下拉列表选中条目左右选择功能)
- JavaWeb——JQuery之DOM操作应用及实践案例总结(DOM内容操作、DOM属性操作、CRUD操作)
- JavaWeb——Filter过滤器快速入门与是否登录验证&过滤敏感词汇案例实战(Filter配置方式、执行流程、生命周期方法、过滤器链)