在临近上线之前,我们系统做了一次压力测试,发现有一个接口在高并发情况下会出现一个死锁的情况。。首先申明…不是我写的,我只是帮忙排查下。

随着对Mysql锁的深入了解,于是就准备写几篇文章来记录下Mysql各种事物和索引的情况下出现死锁的情况。

今天就介绍下在并发插入的情况下,哪几种情况会出现死锁:

INNODB下的各种锁

在介绍锁的时候只会介绍跟本节相关的锁,而且只会讲述大概是什么,至于锁的更加详细的讲解可能会到以后再详细介绍。

行锁

行锁分为写锁和读取锁,读锁(S锁)也可以称之为 共享锁 , 它表示的是任何一个事物都可以读取该行数据(可以被多个事物获取到)。写锁(X锁)也可以称之为排它锁,它表示的是该行数据不允许任何人进行修改,同时也不允许任何事物获取该行事物的S锁,但是普通的 select 语句是可以的。

背景信息一

注意:以下测试都是基于该事物隔离级别和数据库版本

数据库版本:8.0.11

事务隔离级别:REPEATABLE-READ1

2

3

4

5

6

7mysql> SHOW VARIABLES LIKE 'transaction_isolation';

+

| Variable_name | Value |

+

| transaction_isolation | REPEATABLE-READ |

+

1 row in set (0.00 sec)

SQL准备:1

2

3

4

5

6

7

8

9

10create database if not exists test_lock DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

CREATE TABLE test_lock.`test` (

`user_id` varchar(32) NOT NULL,

`user_name` varchar(32) NOT NULL,

`user_password` varchar(16) NOT NULL,

`is_deleted` int(1) NOT NULL,

`phone` varchar(20) NOT NULL,

PRIMARY KEY (`user_id`),

KEY `t1_god` (`user_name`,`user_password`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

准备数据:1

2

3

4

5

6

7

8insert into test_lock.`test` values('a','zhangsan','123456',0,'15112345678');

insert into test_lock.`test` values('b','lisi','lisi123456',0,'15112345678');

insert into test_lock.`test` values('c','wangwu','wangwu123456',0,'15112345678');

insert into test_lock.`test` values('d','caocao','caocao123456',0,'15112345678');

insert into test_lock.`test` values('e','liubei','liubei123456',0,'15112345678');

insert into test_lock.`test` values('f','zhangfei','zhangfei123456',0,'15112345678');

insert into test_lock.`test` values('g','guanyu','guanyu123456',0,'15112345678');

insert into test_lock.`test` values('h','xiaoqiao','xiaoqiao123456',0,'15112345678');

情况一:三个事物都执行同一个Insert语句,第一个事物然后回滚

此时第三个事物会提示死锁,第二个事物正常插入。

复现步骤:

开启三个事物,每一个事物分别执行如下SQL,然后再将第一个事物进行回滚或者提交,然后你就会发现第三个事物发生了死锁。1

2

3

4## DeadLock

start transaction ;

begin;

insert into test_lock.`test` values('i','daqiao','daqiao123456',0,'15112345678');

Mysql提示如下:[2019-08-04 14:33:48] Connected

sql> start transaction

[2019-08-04 14:33:49] completed in 4 ms

sql> begin

[2019-08-04 14:33:49] completed in 6 ms

sql> insert into test_lock.test values(‘i’,’daqiao’,’daqiao123456’,0,’15112345678’)

[2019-08-04 14:34:00] [40001][1213] Deadlock found when trying to get lock; try restarting transaction

[2019-08-04 14:34:00] [40001][1213] Deadlock found when trying to get lock; try restarting transaction

那么打印出Mysql出现死锁的日志:重点日志如下1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32LATEST DETECTED DEADLOCK

------------------------

2019-08-04 06:33:59 0x7f1818599700

*** (1) TRANSACTION:

TRANSACTION 231690, ACTIVE 34 sec inserting

mysql tables in use 1, locked 1

LOCK WAIT 4 lock struct(s), heap size 1136, 2 row lock(s)

MySQL thread id 9, OS thread handle 139741464762112, query id 95 172.17.0.1 root update

/* ApplicationName=IntelliJ IDEA 2019.1.3 */ insert into test_lock.

*** (1) WAITING FOR THIS LOCK TO BE GRANTED:

RECORD LOCKS space id 7 page no 4 n bits 80 index PRIMARY of table `test_lock`.`test` trx id 231690 lock_mode X insert intention waiting

Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0

0: len 8; hex 73757072656d756d; asc supremum;;

*** (2) TRANSACTION:

TRANSACTION 231691, ACTIVE 10 sec inserting

mysql tables in use 1, locked 1

4 lock struct(s), heap size 1136, 2 row lock(s)

MySQL thread id 10, OS thread handle 139741464467200, query id 139 172.17.0.1 root update

/* ApplicationName=IntelliJ IDEA 2019.1.3 */ insert into test_lock.

*** (2) HOLDS THE LOCK(S):

RECORD LOCKS space id 7 page no 4 n bits 80 index PRIMARY of table `test_lock`.`test` trx id 231691 lock mode S

Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0

0: len 8; hex 73757072656d756d; asc supremum;;

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:

RECORD LOCKS space id 7 page no 4 n bits 80 index PRIMARY of table `test_lock`.`test` trx id 231691 lock_mode X insert intention waiting

Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0

0: len 8; hex 73757072656d756d; asc supremum;;

*** WE ROLL BACK TRANSACTION (2)

------------

从以上日志我们可以看到,事物一正在请求该行记录的 X锁 ,事物二持有该行的S锁,但是也在等待获取该行的X锁。

关于Mysql的 insert 逻辑,可以大致理解为如果一个事物正在对一个记录进行 insert,此时 InnoDB 并不会主动的将其加一个锁,而是在主键索引上加一个 trx_id,

当第二个事物检测到该行记录正在被一个活跃的事物持有的时候,此时第二个事物会帮第一个事物的隐式锁住转为显式锁。如下例子:1

2

3

4## DeadLock

start transaction ;

begin;

insert into test_lock.`test` values('i','daqiao','daqiao123456',0,'15112345678');

此时查看Mysql中锁的情况:

可以看到此时Mysql仅仅是在表上加入了一个插入意向锁(IX锁),持有该锁表示该事物在接下来有可能会对自己设计到的行加入排它锁(X锁)The intention locking protocol is as follows:Before a transaction can acquire a shared lock on a row in a table, it must first acquire an IS lock or stronger on the table.

Before a transaction can acquire an exclusive lock on a row in a table, it must first acquire an IX lock on the table.

大意就是如果你想获得一个行的 X锁,那么你就必须先获取表的 IX锁

那么此时再进行第二个事物的插入:1

2

3

4## DeadLock

start transaction ;

begin;

insert into test_lock.`test` values('i','daqiao','daqiao123456',0,'15112345678');

再次查看数据库中的锁:

此时会发现第一个事物已经获取到了行级别的X锁,第二个事物获取到了 IX 锁以及 S锁 。

那么此时第三个事物开启之后数据库中的锁又会是什么样子的呢?

可以发现另外两个事物都在等待获取该行的S锁。然后此时第一个事物进行回滚,此时第三个事物就会提示死锁。

原因

前提结论S锁是可以升级到X锁的

一个S锁需要升级到X锁必须保证只有当前事物持有S锁

死锁原因

当第一个事物回滚之后,第二个事物和第三个事物都会获得到该行的S锁,但是此时第二个事物将要执行 insert 语句,也就是第二个事物正在等待获取该行的X锁,但是此时第三个事物也正在准备 insert,它也在准备获取 X锁,目前这两个事物都持有该行的 S锁 ,而如果需要获取 X锁,则是需要对方释放S锁。如下图:

简单复现步骤:

为了验证上面的情况,我准备如下几个SQL:1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19## 事物一

start transaction ;

begin;

select * from test_lock.test where user_id='h' lock in share mode;

## 事物二

start transaction ;

begin;

select * from test_lock.test where user_id='h' lock in share mode;

## 事物一再执行

update test_lock.`test` set user_name='abc' where user_id = 'h';

## 事物二再执行

update test_lock.`test` set user_name='abc' where user_id = 'h';

## 此时事物二就会提示死锁

这是因为事物一和事物二都在等待对方释放S锁,但是都不肯释放,于是死锁发生了。

情况二三个事物都执行同一个Insert语句,第一个事物然后提交

此时第二个事物和第三个事物都会提示主键冲突,并无死锁出现。

总结

这种情况下的死锁是由于 S锁 升级到 X锁导致的一种死锁,在平常的业务代码中应该尽量避免并发插入一个主键。

mysql 数据库 死锁_Mysql数据库出现死锁的情况(一)相关推荐

  1. mysql 插入加锁_MySQL 是怎么死锁的?

    Java技术栈 www.javastack.cn 关注优质文章 最近总结了一波死锁问题,和大家分享一下. Mysql 锁类型和加锁分析 MySQL有三种锁的级别:页级.表级.行级. 表级锁:开销小,加 ...

  2. mysql 数据库事务处理_MySQL数据库事务及其原理

    基本概念 MySQL 事务主要用于处理操作量大,复杂度高的数据. 银行转账是经典的解释事务的例子.用户A给用户B转账5000元主要步骤可以概括为如下两步. 第一,账户A账户减去5000元: 第二,账户 ...

  3. mysql数据库监控程序_mysql数据库监控利器lepus天兔工具安装和部署

    需要的核心包如下: 以下软件包只需要部署在监控机即可.被监控机无需部署. 1.MySQL 5.0及以上(必须,用来存储监控系统采集的数据) 2.Apache 2.2及以上 (必须,WEB服务器运行服务 ...

  4. mysql数据库语法_MySQL数据库基本语法

    SQL WHAT(SQL是什么?) Structured Query Language:结构化查询语⾔ WHY(为何要使用SQL?) 难道仅仅使用SQL Server Management Studi ...

  5. Mysql常用词汇_mysql 数据库常用单词

    说明:以下单词可能有多种含义,此文档只针对编程做解释.单词不多,熟能生巧,每日认真读读写写,效果不错.如有错误,请谅解并指出,谢谢大家! 黄金超 2017-4-7 连接MySQL数据库: mysql ...

  6. mysql删除原则_MySQL数据库的增删选查

    数据库是专门存储数据对象的容器,这里的数据对象包括表.视图.触发器.存储过程等,其中表是最基本的数据对象. 创建数据库 在 MySQL 数据库中存储数据对象之前,先要创建好数据库. 语法: creat ...

  7. mysql select表达式_MySQL数据库SELECT查询表达式解析

    数据的管理在很大一部分是在进行查找工作,而SELECT占据了很大的一部分 SELECT select_expr [,select_expr...] [ FROM table_reference WHE ...

  8. mysql数据库导出_MySQL数据库导入导出详解[转发]

    1. 概述 MySQL数据库的导入,有两种方法: 1) 先导出数据库SQL脚本,再导入: 2) 直接拷贝数据库目录和文件. 在不同操作系统或MySQL版本情况下,直接拷贝文件的方法可能会有不兼容的情况 ...

  9. mysql断网_mysql数据库断网链接

    {"moduleinfo":{"card_count":[{"count_phone":1,"count":1}],&q ...

  10. 熟悉mysql基本数据库操作系统_MySQL数据库的基本操作

    1.数据库和数据库对象 数据库分为系统数据库和用户数据库. 数据库对象是指存储.管理和使用数据库的不同结构形式,主要包括表.视图.存储过程.函数.触发器和事务. 1.系统数据库 系统数据库是值安装完M ...

最新文章

  1. NeurIPS 2021六篇杰出论文公布,谷歌工程师11年前论文获时间检验奖
  2. 科学家研发出“读心术”,直接将脑电波翻译成文本,错误率低至 3%
  3. 刷牙刷了这么多年,我们居然都搞错了!
  4. Java Web 程序设计----基于SSM框架(正在更新中)
  5. 氨氮吹脱法脱与php有关系吗,吹脱法处理氨氮废水的原理及优缺点分析
  6. Mac OS系统版本与XCode版本的关系
  7. 【你会用代码画年兽吗】20行代码使用JS实现虎年春节倒计时 —— 红红火火过虎年
  8. 彻底卸载acer软件保护卡_宏碁(Acer)传奇 14英寸 新一代7nm六核处理器 真香机 高性能宏基笔记本电脑(R5-4500U 7纳米 16G 512GSSD )...
  9. ffmpeg java调用_macos下ffmpeg使用及java调用
  10. editplus配置刷新
  11. 0x00007FFC4480532C(opencv_world310.dll)处(位于opencv-024.exe中)引发的异常:OxC0000005:读取位置0xFFFFFFFFFF时发生访问冲突
  12. 前端基础知识体系之项目经验篇
  13. 计算机操作系统第三次作业,操作系统第三次作业参考答案
  14. 【IoT】产品设计:关于专利申请,这篇文章就够了
  15. JAVA实现简单电话簿功能
  16. 第4章第3节:如何插入或删除表格的行与列 [PowerPoint精美幻灯片实战教程]
  17. 基于RabbitMQ实现的订单超时功能-记录备查
  18. 小马哥spring编程核心思想_《Spring Boot编程思想(核心篇)》小马哥著 PDF电子书下载...
  19. 芥川龙之介《山药粥》
  20. PyTorch搭建LSTM实现多变量多步长时间序列预测(四):多模型滚动预测

热门文章

  1. scala字符串转int_如何在Scala中将十六进制字符串转换为int?
  2. 浏览器访问图片提示Net::ERR_CONNECTION_RESET
  3. NOSQL 非关系型数据库(redis)
  4. 掌握Mock摆脱后端同学的束缚
  5. 将网卡设为混杂模式_如何将网卡设置为混杂模式
  6. 计算机毕业设计ssm基于网络的景区旅游服务管理系统q57ng系统+程序+源码+lw+远程部署
  7. js 转义特殊字符到 html
  8. 测试人员如何保证测试质量
  9. 【高德地图WEB开发】 入门篇(地图/搜索/经纬度/缩放层级)
  10. 算法训练--学做菜(Java)