栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

mysql死锁解决方法(mysql解决死锁)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

mysql死锁解决方法(mysql解决死锁)

一、前言
在线上发布新功能后,追踪了日志记录,发现有死锁的报错记录。因业务复杂,仅简化问题,先将问题简化复原。特在此记录解决分析过程。

先抛出问题,后附解决方案;

事务A事务B
1、 insert into user_01 (name,age) select name,age user_02
1、update user_02 set name = ‘lisi’ where id = ‘2’
2、update user_02 set name = ‘lisi’ where id = ‘2’
结果:更新成功结果:Deadlock found when trying to get lock; try restarting transaction
二、问题复原过程 1、建表,向表2插入数据
CREATE TABLE `user_01`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `age` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
);
CREATE TABLE `user_01`  (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  `age` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
);
INSERT INTO `user_02` VALUES (2, 'lisi', '15');
2、事务A开始执行 2.1 新建单元测试

2.2 调用的方法有事务注解(保证在一个事务中被提交)

断点至:insertBySelect()方法执行完毕

2.3 navicat中执行SQL,此时SQL在等待状态
update user_02 
set name = 'lisi' where id = '2'
2.4 将程序断点执行完毕

SQL立即死锁

备注: 实际执行的SQL内容

三、问题解决过程 1. 查询当前INNODB日志,包含死锁记录

SQL命令:show engine innodb status;

------------------------
LATEST DETECTED DEADLOCK
------------------------
2022-03-18 23:06:40 0xfcc
# 事务1的信息
*** (1) TRANSACTION:
TRANSACTION 10026282, ACTIVE 4 sec starting index read
mysql tables in use 1, locked 1
# ACTIVE 4 :表示事务活动时间
# starting :当前事务运行的状态
# tables in use 1 : 有一个表被使用
# locked 1 :有一个表锁
LOCK WAIT 2 lock struct(s), heap size 1136, 1 row lock(s)
# LOCK WAIT :事务正在等待锁
# 2 lock struct(s) :该事务的锁链表长度为2,每个链表节点代表该事务持有的一个锁结构,包括表锁,记录锁以及 autoinc 锁等。
# heap size 1184 :为事务分配的锁堆内存大小
# 1 row lock(s) :行锁的数量
MySQL thread id 835727, OS thread handle 14684, query id 59561617 218.69.52.198 root updating
update user_02 set name = 'lisi' where id = '2'
# 上述:事务的线程信息,数据库IP地址和数据库名
*** (1) HOLDS THE LOCK(S):
RECORD LOCKS space id 5749 page no 4 n bits 72 index PRIMARY of table `han`.`user_02` trx id 10026379 lock_mode X locks rec but not gap waiting
# 事务1正在等待主键索引上的 X锁 但是没有 gap锁释放
Record lock, heap no 2 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
 0: len 4; hex 80000002; asc     ;;
 1: len 6; hex 00000098fd0e; asc       ;;
 2: len 7; hex 02000003b30be1; asc        ;;
 3: len 4; hex 6c697369; asc lisi;;
 4: len 2; hex 3135; asc 15;;


*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 5749 page no 4 n bits 72 index PRIMARY of table `han`.`user_02` trx id 10026379 lock_mode X locks rec but not gap waiting
Record lock, heap no 2 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
 0: len 4; hex 80000002; asc     ;;
 1: len 6; hex 00000098fd0e; asc       ;;
 2: len 7; hex 02000003b30be1; asc        ;;
 3: len 4; hex 6c697369; asc lisi;;
 4: len 2; hex 3135; asc 15;;

结论: 事务B 尝试获取X锁

*** (2) TRANSACTION:
TRANSACTION 10026378, ACTIVE 5 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 5 lock struct(s), heap size 1136, 3 row lock(s), undo log entries 1
MySQL thread id 841869, OS thread handle 12380, query id 59596235 218.69.52.198 root updating
update user_02 set name = 'wangwu' where id = '2'

*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 5749 page no 4 n bits 72 index PRIMARY of table `han`.`user_02` trx id 10026378 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;;

Record lock, heap no 2 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
 0: len 4; hex 80000002; asc     ;;
 1: len 6; hex 00000098fd0e; asc       ;;
 2: len 7; hex 02000003b30be1; asc        ;;
 3: len 4; hex 6c697369; asc lisi;;
 4: len 2; hex 3135; asc 15;;


*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 5749 page no 4 n bits 72 index PRIMARY of table `han`.`user_02` trx id 10026378 lock_mode X locks rec but not gap waiting
Record lock, heap no 2 PHYSICAL RECORD: n_fields 5; compact format; info bits 0
 0: len 4; hex 80000002; asc     ;;
 1: len 6; hex 00000098fd0e; asc       ;;
 2: len 7; hex 02000003b30be1; asc        ;;
 3: len 4; hex 6c697369; asc lisi;;
 4: len 2; hex 3135; asc 15;;

●事务B 正在等待的更新意向排他锁,刚好正在事务A的怀里。
●事务A 持有间隙锁,正在等待更新意向排它锁。

2. 结论

按照如下顺序:
事务A(S锁)→ 事务B(X锁) → 事务A(X锁) :会导致死锁发生(由mysql死锁检测机制触发)
解决方案:将事务A的操作升级为X锁。
具体操作包括:
1)将事务A操作1进行升级:select …for update ,即升级为X锁(仅适用于for update)
2)加入分布式锁,将事务A、B隔离开来执行(一定程度降低效率,不建议使用,根据实际业务来决定)

3. select加锁分析

基础知识

锁类型
共享锁(S锁):假设事务T1对数据A加上共享锁,那么事务T2可以读数据A,不能修改数据A。
排他锁(X锁):假设事务T1对数据A加上共享锁,那么事务T2不能读数据A,不能修改数据A。
我们通过update、delete等语句加上的锁都是行级别的锁。只有LOCK TABLE … READ和LOCK TABLE … WRITE才能申请表级别的锁。
意向共享锁(IS锁):一个事务在获取(任何一行/或者全表)S锁之前,一定会先在所在的表上加IS锁。
意向排他锁(IX锁):一个事务在获取(任何一行/或者全表)X锁之前,一定会先在所在的表上加IX锁。

select * from table where id = ?;
执行的是快照读,读的是数据库记录的快照版本,是不加锁的。
select * from table where id = ? lock in share mode;
会对读取记录加S锁 (共享锁)
select * from table where id = ? for update
会对读取记录加X锁 (排他锁)
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/776115.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号