mysql insert 锁
撸了今年阿里、头条和美团的面试,我有一个重要发现.......>>>
多线程插入mysql时会发生死锁。
数据库test中,id1和id2是联合主键
当前数据库test内容为空。mysql引擎是:InnoDB,隔离级别为REPEATABLE-READ
情况一:
线程A开启事务:
mysql> start transaction;
Query OK, 0 rows affected
mysql>
线程B开启事务:
mysql> start transaction;
Query OK, 0 rows affected
mysql>
线程A,插入数据:
mysql> start transaction;
Query OK, 0 rows affectedmysql> INSERT ignore into test values ('1', '1'),('2', '2'),('3','3');
Query OK, 3 rows affected
Records: 3 Duplicates: 0 Warnings: 0mysql>
线程A没有commit,所以数据('1', '1'),('2', '2'),('3','3')被上锁,
线程B这时也插入数据:
mysql> start transaction;
Query OK, 0 rows affectedmysql> INSERT ignore into test values ('2', '2'),('4','4');
等待中....
因为数据('2','2')被上锁,所以等待线程A释放锁,此时数据('4','4')还没有被上锁。线程A可以插入('4','4');
mysql> start transaction;
Query OK, 0 rows affectedmysql> INSERT ignore into test values ('1', '1'),('2', '2'),('3','3');
Query OK, 3 rows affected
Records: 3 Duplicates: 0 Warnings: 0mysql> INSERT ignore into test values ('5', '5'),('4', '4')
;
Query OK, 2 rows affected
Records: 2 Duplicates: 0 Warnings: 0mysql>
线程A提交:
mysql> start transaction;
Query OK, 0 rows affectedmysql> INSERT ignore into test values ('1', '1'),('2', '2'),('3','3');
Query OK, 3 rows affected
Records: 3 Duplicates: 0 Warnings: 0mysql> INSERT ignore into test values ('5', '5'),('4', '4')
;
Query OK, 2 rows affected
Records: 2 Duplicates: 0 Warnings: 0mysql> commit;
Query OK, 0 rows affectedmysql>
线程B提交:
mysql> start transaction;
Query OK, 0 rows affectedmysql> INSERT ignore into test values ('2', '2'),('4','4');
Query OK, 0 rows affected
Records: 2 Duplicates: 2 Warnings: 2mysql> commit;
Query OK, 0 rows affected
情况二:
线程A开启事务:
mysql> start transaction;
Query OK, 0 rows affected
mysql>
线程B开启事务:
mysql> start transaction;
Query OK, 0 rows affected
mysql>
线程A,插入数据:
mysql> start transaction;
Query OK, 0 rows affectedmysql> INSERT ignore into test values ('1', '1'),('2', '2'),('3','3');
Query OK, 3 rows affected
Records: 3 Duplicates: 0 Warnings: 0mysql>
线程A没有commit,所以数据('1', '1'),('2', '2'),('3','3')被上锁,
线程B这时也插入数据:
mysql> start transaction;
Query OK, 0 rows affectedmysql> INSERT ignore into test values ('4', '4'),('2','2'),('5','5');
等待中....
因为数据('2','2')被上锁,所以等待线程A释放锁,此时数据('4','4')已经成功执行被上锁。线程A插入('4','4');会造成死锁
A线程插入('4','4'),('5','5'):
mysql> INSERT ignore into test values ('4', '4'),('6', '6')
;
Query OK, 2 rows affected
Records: 2 Duplicates: 0 Warnings: 0mysql>
此时B线程检测到死锁:
mysql> INSERT ignore into test values ('4', '4'),('2','2'),('5','5');
1213 - Deadlock found when trying to get lock; try restarting transaction
mysql>
也就是说
A线程执行insert ignore into test values ('1', '1'),('2', '2');能执行成功,会给('1', '1'),('2', '2')加锁
B线程执行insert ignore into test values ('3', '3'),('2', '2'),('4','4');检测('3','3')没有加锁,然后给('3','3')加上锁,('2','2')检测到锁,被A线程锁住,等待锁释放,这时('4','4')这条数据没有加锁。
接下来:
- 如果A线程执行insert ignore into test values ('3', '3');时 检测到 ('3', '3')有锁,被B线程锁住,互相等待释放锁,这时就形成了死锁。
- 如果A线程执行insert ignore into test values ('4', '4');时 没检测到('4','4')有锁,可以正常执行。这时如果A线程commit,B线程就会提示重复数据。但是不形成死锁。
死锁的方向
线程B死锁:
线程A执行:
mysql> start transaction;
Query OK, 0 rows affectedmysql> INSERT ignore into test values ('1', '1'),('2', '2');
Query OK, 2 rows affected
Records: 2 Duplicates: 0 Warnings: 0mysql>
线程B执行:
mysql> start transaction;
Query OK, 0 rows affectedmysql> INSERT into test values ('3', '3'),('2','2');
等待中....
然后线程A执行:
mysql> INSERT ignore into test values ('3', '3');
Query OK, 1 row affectedmysql>
这时B线程检测到死锁,结束等待,并且自动回滚,线程A正常执行。
B检测到死锁:
mysql> INSERT into test values ('3', '3'),('2','2');
1213 - Deadlock found when trying to get lock; try restarting transaction
mysql>
========
A线程执行:
mysql> start transaction;
Query OK, 0 rows affectedmysql> INSERT ignore into test values ('1', '1'),('2', '2'),('9','9'),('8','8');
Query OK, 4 rows affected
Records: 4 Duplicates: 0 Warnings: 0mysql>
B线程执行:
mysql> start transaction;
Query OK, 0 rows affectedmysql> INSERT into test values ('3', '3'),('2','2');
等待中
然后A线程执行:
mysql> INSERT ignore into test values ('3', '3');
Query OK, 1 row affectedmysql>
B线程检测到死锁,停止等待,自动回滚:
ysql> INSERT into test values ('3', '3'),('2','2');
1213 - Deadlock found when trying to get lock; try restarting transaction
mysql>
线程A死锁:
线程A:
mysql> start transaction;
Query OK, 0 rows affectedmysql> INSERT ignore into test values ('1', '1'),('2', '2');
Query OK, 2 rows affected
Records: 2 Duplicates: 0 Warnings: 0mysql>
线程B:
mysql> start transaction;
Query OK, 0 rows affectedmysql> INSERT into test values ('3', '3'),('4','4'),('2','2');
等待中
这时A线程执行:
mysql> INSERT ignore into test values ('3', '3');
1213 - Deadlock found when trying to get lock; try restarting transaction
mysql>
检测到死锁,死锁在A线程这边,A线程自动回滚,B线程结束等待,正常提交
mysql> INSERT into test values ('3', '3'),('4','4'),('2','2');
Query OK, 3 rows affected
Records: 3 Duplicates: 0 Warnings: 0mysql>
========
线程A执行:
mysql> start transaction;
Query OK, 0 rows affectedmysql> INSERT ignore into test values ('1', '1'),('2', '2');
Query OK, 2 rows affected
Records: 2 Duplicates: 0 Warnings: 0mysql>
线程B执行:
mysql> start transaction;
Query OK, 0 rows affectedmysql> insert into test values ('3','3'),('4','4'),('5','5'),('2','2');
Query OK, 3 rows affected
Records: 3 Duplicates: 0 Warnings: 0mysql>
这时A线程执行:
mysql> INSERT ignore into test values ('3', '3');
1213 - Deadlock found when trying to get lock; try restarting transaction
mysql>
A线程检测到死锁,并且自动回滚,释放锁,B线程结束等待。
猜想:谁加锁的数据少,那么谁就检测到死锁,就先释放锁。
例如:线程A执行:
mysql> start transaction;
Query OK, 0 rows affectedmysql> insert ignore into test values ('1','1'),('2','2');
Query OK, 2 rows affected
Records: 2 Duplicates: 0 Warnings: 0mysql>
线程A加锁数据:('1','1'),('2','2')
线程B:
mysql> start transaction;
Query OK, 0 rows affectedmysql> insert into test values ('3','3'),('4','4'),('5','5'),('2','2');
等待中....
线程B加锁数据:('3','3'),('4','4'),('5','5')
然后A线程执行:
mysql> insert ignore into test values ('6','6'),('7','7'),('8','8'),('9','9'),('3','3');
此时A线程加锁数据为:('1','1'),('2','2'),('6','6'),('7','7'),('8','8'),('9','9')
A线程加锁数据多于B线程,所以B线程检测到死锁,主动释放锁,
B线程:
mysql> insert into test values ('3','3'),('4','4'),('5','5'),('2','2');
1213 - Deadlock found when trying to get lock; try restarting transaction
mysql>
说明谁加锁的数据少,那么谁就检测到死锁,就先释放锁。
mysql insert 锁相关推荐
- mysql insert锁机制
一.前言 上周遇到一个因insert而引发的死锁问题,其成因比较令人费解. 于是想要了解一下insert加锁机制,但是发现网上介绍的文章比较少且零散,挖掘过程比较忙乱. 本以为只需要系统学习一个较完全 ...
- mysql insert锁 innodb_mysql – 处理ON INSERT触发器时如何锁定innodb表?
我有两个innodb表: 用品 id | title | sum_votes ------------------------------ 1 | art 1 | 5 2 | art 2 | 8 3 ...
- insert 锁表 mysql_mysql insert锁机制【转】
最近再找一些MySQL锁表原因,整理出来一部分sql语句会锁表的,方便查阅,整理的不是很全,都是工作中碰到的,会持续更新 笔者能力有限,如果有不正确的,或者不到位的地方,还请大家指出来,方便你我,方便 ...
- mysql insert into select大量数据插入比较慢_史上最全MySQL锁机制
本文主要记录学习MyISAM 和 InnoDB 这两个存储引擎. 为什么要学习锁机制 锁是计算机协调多个进程或线程并发访问某一资源的机制. 因为数据也是一种供许多用户共享的资源,如何保证数据并发访问的 ...
- mysql insert是锁表还是锁行_mysql 锁表还是锁行
关于mysql的锁行还是锁表,这个问题,今天算是有了一点头绪,mysql 中 innodb是锁行的,但是项目中居然出现了死锁,锁表的情况.为什么呢?先看一下这篇文章. 做项目时由于业务逻辑的需要,必须 ...
- mysql乐观锁处理超卖_通过乐观锁解决库存超卖的问题
前言 在通过多线程来解决高并发的问题上,线程安全往往是最先需要考虑的问题,其次才是性能.库存超卖问题是有很多种技术解决方案的,比如悲观锁,分布式锁,乐观锁,队列串行化,Redis原子操作等.本篇通过M ...
- MySql各种锁机制的学习
加锁的目的: 数据库是一个多用户使用的共享资源.当多个用户并发地存取数据时,在数据库中就会产生多个事务同时存取同一数据的情况.若对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性.锁 ...
- MySQL InnoDB锁
2019独角兽企业重金招聘Python工程师标准>>> InnoDB与MyISAM的最大不同有两点:一是支持事务(TRANSACTION):二是采用了行级锁.行级锁与表级锁本来就有许 ...
- 一文读懂MySQL事务锁、事务级别
锁 性能分:乐观(比如使用version字段比对,无需等待).悲观(需要等待其他事务) 乐观锁,如它的名字那样,总是认为别人不会去修改,只有在提交更新的时候去检查数据的状态.通常是给数据增加一个字段来 ...
最新文章
- sklearn SVM(支持向量机)模型使用RandomSearchCV获取最优参数及可视化​​​​​​​
- [LeetCode]Count of Range Sum
- python解决实际问题的代码_Python代码规范问题及解决
- Request_原理
- OpenCV进行图像相似度对比的几种办法
- 设计模式之原型模式(Prototype)
- 美国在线计算机硕士申请难度,美国计算机硕士申请条件有哪些?看完这篇文章你就清楚了...
- JS实现自动轮播图效果(自适应屏幕宽度+手机触屏滑动)
- Windows下C语言的Socket编程例子(TCP和UDP)
- 高斯滤波程序编写 opencv C++ CSU
- 坚持每一天,不忘初心,正经的前端学习(705)
- [转帖]身份证前两位是怎么来的
- Html + JQuery 点击图片弹出视频加蒙版,全局居中并且可关闭
- python列索引行的数据公式_python中pandas数据分析基础3(数据索引、数据分组与分组运算、数据离散化、数据合并)...
- Duplicate entry for key 'PRIMARY'
- tilemap软件使用_使用Tilemap的等距2D环境
- Python 批量提取 Word 中表格内容,一键写入 Excel
- JavaScript AMD 模块
- 如何快速高效出高质量效果图
- linux三种网络模式