撸了今年阿里、头条和美团的面试,我有一个重要发现.......>>>

多线程插入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')这条数据没有加锁。

接下来:

  1. 如果A线程执行insert ignore into test values ('3', '3');时 检测到 ('3', '3')有锁,被B线程锁住,互相等待释放锁,这时就形成了死锁。
  2. 如果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 锁相关推荐

  1. mysql insert锁机制

    一.前言 上周遇到一个因insert而引发的死锁问题,其成因比较令人费解. 于是想要了解一下insert加锁机制,但是发现网上介绍的文章比较少且零散,挖掘过程比较忙乱. 本以为只需要系统学习一个较完全 ...

  2. mysql insert锁 innodb_mysql – 处理ON INSERT触发器时如何锁定innodb表?

    我有两个innodb表: 用品 id | title | sum_votes ------------------------------ 1 | art 1 | 5 2 | art 2 | 8 3 ...

  3. insert 锁表 mysql_mysql insert锁机制【转】

    最近再找一些MySQL锁表原因,整理出来一部分sql语句会锁表的,方便查阅,整理的不是很全,都是工作中碰到的,会持续更新 笔者能力有限,如果有不正确的,或者不到位的地方,还请大家指出来,方便你我,方便 ...

  4. mysql insert into select大量数据插入比较慢_史上最全MySQL锁机制

    本文主要记录学习MyISAM 和 InnoDB 这两个存储引擎. 为什么要学习锁机制 锁是计算机协调多个进程或线程并发访问某一资源的机制. 因为数据也是一种供许多用户共享的资源,如何保证数据并发访问的 ...

  5. mysql insert是锁表还是锁行_mysql 锁表还是锁行

    关于mysql的锁行还是锁表,这个问题,今天算是有了一点头绪,mysql 中 innodb是锁行的,但是项目中居然出现了死锁,锁表的情况.为什么呢?先看一下这篇文章. 做项目时由于业务逻辑的需要,必须 ...

  6. mysql乐观锁处理超卖_通过乐观锁解决库存超卖的问题

    前言 在通过多线程来解决高并发的问题上,线程安全往往是最先需要考虑的问题,其次才是性能.库存超卖问题是有很多种技术解决方案的,比如悲观锁,分布式锁,乐观锁,队列串行化,Redis原子操作等.本篇通过M ...

  7. MySql各种锁机制的学习

    加锁的目的: 数据库是一个多用户使用的共享资源.当多个用户并发地存取数据时,在数据库中就会产生多个事务同时存取同一数据的情况.若对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的一致性.锁 ...

  8. MySQL InnoDB锁

    2019独角兽企业重金招聘Python工程师标准>>> InnoDB与MyISAM的最大不同有两点:一是支持事务(TRANSACTION):二是采用了行级锁.行级锁与表级锁本来就有许 ...

  9. 一文读懂MySQL事务锁、事务级别

    锁 性能分:乐观(比如使用version字段比对,无需等待).悲观(需要等待其他事务) 乐观锁,如它的名字那样,总是认为别人不会去修改,只有在提交更新的时候去检查数据的状态.通常是给数据增加一个字段来 ...

最新文章

  1. sklearn SVM(支持向量机)模型使用RandomSearchCV获取最优参数及可视化​​​​​​​
  2. [LeetCode]Count of Range Sum
  3. python解决实际问题的代码_Python代码规范问题及解决
  4. Request_原理
  5. OpenCV进行图像相似度对比的几种办法
  6. 设计模式之原型模式(Prototype)
  7. 美国在线计算机硕士申请难度,美国计算机硕士申请条件有哪些?看完这篇文章你就清楚了...
  8. JS实现自动轮播图效果(自适应屏幕宽度+手机触屏滑动)
  9. Windows下C语言的Socket编程例子(TCP和UDP)
  10. 高斯滤波程序编写 opencv C++ CSU
  11. 坚持每一天,不忘初心,正经的前端学习(705)
  12. [转帖]身份证前两位是怎么来的
  13. Html + JQuery 点击图片弹出视频加蒙版,全局居中并且可关闭
  14. python列索引行的数据公式_python中pandas数据分析基础3(数据索引、数据分组与分组运算、数据离散化、数据合并)...
  15. Duplicate entry for key 'PRIMARY'
  16. tilemap软件使用_使用Tilemap的等距2D环境
  17. Python 批量提取 Word 中表格内容,一键写入 Excel
  18. JavaScript AMD 模块
  19. 如何快速高效出高质量效果图
  20. linux三种网络模式

热门文章

  1. 详解ASP.NET页面的aspx扩展
  2. Struts 验证框架实现步骤
  3. pid控制器c51语言编程,51单片机电机pid控制系统程序
  4. SELECT LAST_INSERT_ID() 的使用和注意事项
  5. 详谈PHP垃圾回收机制
  6. 基于mysqli封装的数据库类
  7. CodeReview学习与总结
  8. Mysql的垂直分表-新建
  9. 狼人杀服务器维护时间,狼人杀官 方将于11月30日进行停机维护
  10. Linux多进程拷贝fork,浅析linux中fork函数