文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Deadlock found when trying to get lock; try restarting transaction 【MySQL死锁问题解决】

2023-08-20 12:10

关注

视频地址: https://www.bilibili.com/video/bv1zY411N7tB



最近在调试接口的时候遇到了MySQL死锁问题,我自己测试的时候一切都好好的,但在并发下,就死锁了

其实死锁问题,并没有一个类似“万金油”的解决办法,解铃还需系铃人,能做的只有写这个代码的人自己去解决

第一次出现死锁,想必你也会和我一样整个人都是懵的,不知道如何下手,等你看过下面的文章明白了死锁,就不会害怕了

死锁异常

2022-06-15 16:05:22.216 ERROR 38907 --- [  XNIO-1 task-4] c.i.c.exception.GlobalExceptionHandler   : ### Error updating database.  Cause: com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction### The error may exist in file [/Users/xiaodaoxian/Desktop/work/code/ideamake-market-cloud-third-dock/target/classes/mapper/YxxWkBatchDataMapper.xml]### The error may involve defaultParameterMap### The error occurred while setting parameters### SQL: DELETE FROM xdx_test_two WHERE user_id = ?### Cause: com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction; Deadlock found when trying to get lock; try restarting transaction; nested exception is com.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction

一、理论(重要)

所谓的死锁,一定是两个线程互相等待对方的资源。对于MySQL 来说,那就是两个事物锁住了对方的数据。

MySQL的innodb有 表锁、行锁,如果锁表那死锁的概率很大,一般我们操作都是带有参数的 where user_id = 'xxx'

理论上如果写delete or update 的时候带了上面的条件,按照我们的理解那就是行锁,并发情况下只要我们参数不一致那永远不会造成死锁

但实际情况总不会如人意的,我造成死锁的2个SQL就是上面这样的操作,两个删除都是带了 where,但还是锁表了


MySQL InnoDB 引擎下,delete/update操作where后面的条件如果没有走索引,会锁表(MySQL 5.6/7 版本验证)


请注意上面我说的是 两个事物互相锁住了对方的资源 而并不是简单的两个SQL,这也就是为什么需要熟悉业务代码的人去解决,一个复杂的业务可能涉及到七八张表的操作。


上面说了死锁产生的主要原因,下面再来说说死锁在业务中产生的几种可能和解决办法

  1. 一般来说我们代码不管哪个线程进来都是按顺序执行的,但实际情况是我们在代码中写了各种 if else 等条件语句,这样就导致每个请求实际操作表的顺序可能不一致了,就可能造成死锁(我遇到就是这样的),但这种情况大部分我们把表索引创建好,不出现锁表就没事了。
  2. 并发下相同的业务参数去执行,第一个事物还没提交后面的事物又来了,这种我们加分布式锁就好了

二、死锁实践

2-1、建表

CREATE TABLE `xdx_test_one` (  `id` int(11) NOT NULL AUTO_INCREMENT,  `user_id` varchar(32) DEFAULT NULL COMMENT '用户uuid',  PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='测试表one';CREATE TABLE `xdx_test_two` (  `id` int(11) NOT NULL AUTO_INCREMENT,  `user_id` varchar(32) DEFAULT NULL COMMENT '用户uuid',  PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COMMENT='测试表two';

2-2、代码

2-2-1、controller

@GetMapping("/testLock")public void testLock(@RequestParam String params) throws InterruptedException {    dataServiceImpl.testLock(params);}

2-2-2、service

@Transactional(rollbackFor = Exception.class)public void testLock(String params) throws InterruptedException {    if ("one".equals(params)) {        dataMapper.deleteOne(UUID.randomUUID().toString().substring(10, 18));        System.out.println(params + " 获取 xdx_test_one 表锁");        Thread.sleep(2000);    }    dataMapper.deleteTwo(UUID.randomUUID().toString().substring(10, 18));    System.out.println(params + " 获取 xdx_test_two 表锁");    if ("two".equals(params)) {        dataMapper.deleteOne(UUID.randomUUID().toString().substring(10, 18));        System.out.println(params + " 获取 xdx_test_one 表锁");    }}

2-2-3、mapper

<delete id="deleteOne">    DELETE FROM xdx_test_one WHERE user_id = #{substring}delete><delete id="deleteTwo">    DELETE FROM xdx_test_two WHERE user_id = #{substring}delete>

2-3、测试

按照顺序快速的请求下面的url, 你就会看到上面的异常了

http://127.0.0.1:8080/testLock?parmas=one
http://127.0.0.1:8080/testLock?parmas=two

2-4、其它

我们要解决上面的死锁其实很简单,只需要给上面的 user_id 加一个索引就好了


三、死锁分析


3-1、阿里云日志分析

死锁我们一般是要看日志进行分析处理,其实只要找到两个事物之间谁拥有了对方的哪个锁即可,但原始的MySQL日志不大好看,刚好我们是使用的阿里云的服务版MySQL,它会把死锁日志进行分析以表格的方式展示,刚刚我们测试的死锁,表格呈现如下

在这里插入图片描述

可以先大致看一下这个表结构,应该是很清晰的,不过这个表是存在一点问题的,那就是 事物1 是持有 yx_mc.xdx_test_two 的锁 不然是不构成死锁,这个阿里云解释说我们使用的数据库版本比较老,在新的版本已经解决了这个问题。


3-2、原始日志分析

看完了上面的表,我们对死锁的组成应该有了进一步的理解,下面我们来看看MySQL的原始死锁日志

------------------------LATEST DETECTED DEADLOCK------------------------2022-06-16 17:25:01 7fde0b4a3700*** (1) TRANSACTION:TRANSACTION 36291462, ACTIVE 0.717 sec fetching rowsmysql tables in use 1, locked 1LOCK WAIT 5 lock struct(s), heap size 1184, 6 row lock(s), undo log entries 5LOCK BLOCKING MySQL thread id: 576129097 block 307687953MySQL thread id 307687953, OS thread handle 0x7fdeda9fa700, query id 1317704191 10.19.22.58 yx_property_test updatingDELETE FROM xdx_test_one WHERE user_id = '11111'*** (1) WAITING FOR THIS LOCK TO BE GRANTED:RECORD LOCKS space id 3212 page no 3 n bits 88 index `PRIMARY` of table `yx_mc`.`xdx_test_one` trx id 36291462 lock_mode X locks rec but not gap waitingRecord lock, heap no 12 PHYSICAL RECORD: n_fields 4; compact format; info bits 32 0: len 4; hex 8000000b; asc     ;; 1: len 6; hex 00000229c378; asc    ) x;; 2: len 7; hex 0f0000001b0c25; asc       %;; 3: len 5; hex 3131313131; asc 11111;;*** (2) TRANSACTION:TRANSACTION 36291448, ACTIVE 2.005 sec fetching rowsmysql tables in use 1, locked 15 lock struct(s), heap size 1184, 7 row lock(s), undo log entries 6MySQL thread id 576129097, OS thread handle 0x7fde0b4a3700, query id 1317704227 10.19.22.58 yx_property_test updatingDELETE FROM xdx_test_two WHERE user_id = '22222'*** (2) HOLDS THE LOCK(S):RECORD LOCKS space id 3212 page no 3 n bits 88 index `PRIMARY` of table `yx_mc`.`xdx_test_one` trx id 36291448 lock_mode X locks rec but not gapRecord lock, heap no 12 PHYSICAL RECORD: n_fields 4; compact format; info bits 32 0: len 4; hex 8000000b; asc     ;; 1: len 6; hex 00000229c378; asc    ) x;; 2: len 7; hex 0f0000001b0c25; asc       %;; 3: len 5; hex 3131313131; asc 11111;;Record lock, heap no 13 PHYSICAL RECORD: n_fields 4; compact format; info bits 32 0: len 4; hex 8000000c; asc     ;; 1: len 6; hex 00000229c378; asc    ) x;; 2: len 7; hex 0f0000001b0c48; asc       H;; 3: len 5; hex 3131313131; asc 11111;;Record lock, heap no 14 PHYSICAL RECORD: n_fields 4; compact format; info bits 32 0: len 4; hex 8000000d; asc     ;; 1: len 6; hex 00000229c378; asc    ) x;; 2: len 7; hex 0f0000001b0c6b; asc       k;; 3: len 5; hex 3131313131; asc 11111;;Record lock, heap no 15 PHYSICAL RECORD: n_fields 4; compact format; info bits 32 0: len 4; hex 8000000e; asc     ;; 1: len 6; hex 00000229c378; asc    ) x;; 2: len 7; hex 0f0000001b0c8e; asc        ;; 3: len 5; hex 3131313131; asc 11111;;Record lock, heap no 16 PHYSICAL RECORD: n_fields 4; compact format; info bits 32 0: len 4; hex 8000000f; asc     ;; 1: len 6; hex 00000229c378; asc    ) x;; 2: len 7; hex 0f0000001b0cb1; asc        ;; 3: len 5; hex 3131313131; asc 11111;;Record lock, heap no 17 PHYSICAL RECORD: n_fields 4; compact format; info bits 32 0: len 4; hex 80000010; asc     ;; 1: len 6; hex 00000229c378; asc    ) x;; 2: len 7; hex 0f0000001b0cd4; asc        ;; 3: len 5; hex 3131313131; asc 11111;;*** (2) WAITING FOR THIS LOCK TO BE GRANTED:RECORD LOCKS space id 3213 page no 3 n bits 88 index `PRIMARY` of table `yx_mc`.`xdx_test_two` trx id 36291448 lock_mode X locks rec but not gap waitingRecord lock, heap no 18 PHYSICAL RECORD: n_fields 4; compact format; info bits 32 0: len 4; hex 80000017; asc     ;; 1: len 6; hex 00000229c386; asc    )  ;; 2: len 7; hex 190000002116e0; asc     !  ;; 3: len 5; hex 3232323232; asc 22222;;*** WE ROLL BACK TRANSACTION (1)

N、其它

N-1、是不是真的需要事物

其实我们可以反过来想一想,我们的代码是不是一定要加锁,有时候一个复杂的业务,你加锁,会不断的出现死锁,很难根除。

换个角度,如果我们去掉事物,是不是就没有死锁了?你可能觉得不加事物数据会异常,但是想一想如果频繁产生死锁你的数据不也没办法保证吗?如果我们把所有的异常都解决是不是就没问题了?


N-2、拆分事物的颗粒度

同上一个,如果事物粒度太大了,造成死锁的可能性就很大。我们可以根据业务去进行细分,把一个大的事物拆分成多个小的事物,以此来减少死锁的可能性。


N-3、如果只有一个表是否会死锁

只操作一个表是不会死锁的,第一个事物获取了锁,第二个事物就会进入等待,所以不会出现死锁。


N-4、同一个代码是不是一定会造成死锁

我们知道MySQL里面有一个关键字 EXPLAIN ,它可以分析SQL执行的结果,但实际上一定就按照这个去执行么?其实不然的,还有一个SQL优化器,最终执行的方式是由它来决定的。

上面同样的代码,在我本地数据库 where 后面的条件不管是什么都会造成死锁,而在阿里云的数据库上不会,必须要扫描到真实存在数据才会死锁。


N-5、产生死锁的两个事物怎么办?

从目前的数据来看,事物1 会执行成功,事物2 会回滚

来源地址:https://blog.csdn.net/Tomwildboar/article/details/125299471

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-数据库
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯