MySQL死锁问题分析及解决方法实例详解
作者:shichen2014 发布时间:2024-01-23 12:40:18
MySQL死锁问题是很多程序员在项目开发中常遇到的问题,现就MySQL死锁及解决方法详解如下:
1、MySQL常用存储引擎的锁机制
MyISAM和MEMORY采用表级锁(table-level locking)
BDB采用页面锁(page-level locking)或表级锁,默认为页面锁
InnoDB支持行级锁(row-level locking)和表级锁,默认为行级锁
2、各种锁特点
表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低
行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高
页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般
3、各种锁的适用场景
表级锁更适合于以查询为主,只有少量按索引条件更新数据的应用,如Web应用
行级锁则更适合于有大量按索引条件并发更新数据,同时又有并发查询的应用,如一些在线事务处理系统
4、死锁
是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。
表级锁不会产生死锁.所以解决死锁主要还是针对于最常用的InnoDB.
5、死锁举例分析
在MySQL中,行级锁并不是直接锁记录,而是锁索引。索引分为主键索引和非主键索引两种,如果一条sql语句操作了主键索引,MySQL就会锁定这条主键索引;如果一条语句操作了非主键索引,MySQL会先锁定该非主键索引,再锁定相关的主键索引。
在UPDATE、DELETE操作时,MySQL不仅锁定WHERE条件扫描过的所有索引记录,而且会锁定相邻的键值,即所谓的next-key locking。
例如,一个表db.tab_test,结构如下:
id:主键;
state:状态;
time:时间;
索引:idx_1 (state, time)
出现死锁日志如下:
***(1) TRANSACTION:
TRANSACTION 0 677833455, ACTIVE 0 sec, process no 11393, OS thread id 278546 starting index read
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 320
MySQL thread id 83, query id 162348740 dcnet03 dcnet Searching rows for update
update tab_test set state=1064,time=now() where state=1061 and time < date_sub(now(), INTERVAL 30 minute) (任务1的sql语句)
***(1) WAITING FOR THIS LOCK TO BE GRANTED: (任务1等待的索引记录)
RECORD LOCKS space id 0 page no 849384 n bits 208 index `PRIMARY` of table `db/tab_test` trx id 0 677833455 _mode X locks rec but not gap waiting
Record lock, heap no 92 PHYSICAL RECORD: n_fields 11; compact format; info bits 0
0: len 8; hex 800000000097629c; asc b ;; 1: len 6; hex 00002866eaee; asc (f ;; 2: len 7; hex 00000d40040110; asc @ ;; 3: len 8; hex 80000000000050b2; asc P ;; 4: len 8; hex 800000000000502a; asc P*;; 5: len 8; hex 8000000000005426; asc T&;; 6: len 8; hex 800012412c66d29c; asc A,f ;; 7: len 23; hex 75706c6f6164666972652e636f6d2f6 8616e642e706870; asc xxx.com/;; 8: len 8; hex 800000000000042b; asc +;; 9: len 4; hex 474bfa2b; asc GK +;; 10: len 8; hex 8000000000004e24; asc N$;;
*** (2) TRANSACTION:
TRANSACTION 0 677833454, ACTIVE 0 sec, process no 11397, OS thread id 344086 updating or deleting, thread declared inside InnoDB 499
mysql tables in use 1, locked 1
3 lock struct(s), heap size 320, undo log entries 1
MySQL thread id 84, query id 162348739 dcnet03 dcnet Updating update tab_test set state=1067,time=now () where id in (9921180) (任务2的sql语句)
*** (2) HOLDS THE LOCK(S): (任务2已获得的锁)
RECORD LOCKS space id 0 page no 849384 n bits 208 index `PRIMARY` of table `db/tab_test` trx id 0 677833454 lock_mode X locks rec but not gap
Record lock, heap no 92 PHYSICAL RECORD: n_fields 11; compact format; info bits 0
0: len 8; hex 800000000097629c; asc b ;; 1: len 6; hex 00002866eaee; asc (f ;; 2: len 7; hex 00000d40040110; asc @ ;; 3: len 8; hex 80000000000050b2; asc P ;; 4: len 8; hex 800000000000502a; asc P*;; 5: len 8; hex 8000000000005426; asc T&;; 6: len 8; hex 800012412c66d29c; asc A,f ;; 7: len 23; hex 75706c6f6164666972652e636f6d2f6 8616e642e706870; asc uploadfire.com/hand.php;; 8: len 8; hex 800000000000042b; asc +;; 9: len 4; hex 474bfa2b; asc GK +;; 10: len 8; hex 8000000000004e24; asc N$;;
*** (2) WAITING FOR THIS LOCK TO BE GRANTED: (任务2等待的锁)
RECORD LOCKS space id 0 page no 843102 n bits 600 index `idx_1` of table `db/tab_test` trx id 0 677833454 lock_mode X locks rec but not gap waiting
Record lock, heap no 395 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
0: len 8; hex 8000000000000425; asc %;; 1: len 8; hex 800012412c66d29c; asc A,f ;; 2: len 8; hex 800000000097629c; asc b ;;
*** WE ROLL BACK TRANSACTION (1)
(回滚了任务1,以解除死锁)
原因分析:
当“update tab_test set state=1064,time=now() where state=1061 and time < date_sub(now(), INTERVAL 30 minute)”执行时,MySQL会使用idx_1索引,因此首先锁定相关的索引记录,因为idx_1是非主键索引,为执行该语句,MySQL还会锁定主键索引。
假设“update tab_test set state=1067,time=now () where id in (9921180)”几乎同时执行时,本语句首先锁定主键索引,由于需要更新state的值,所以还需要锁定idx_1的某些索引记录。
这样第一条语句锁定了idx_1的记录,等待主键索引,而第二条语句则锁定了主键索引记录,而等待idx_1的记录,这样死锁就产生了。
6、解决办法
拆分第一条sql,先查出符合条件的主键值,再按照主键更新记录:
select id from tab_test where state=1061 and time < date_sub(now(), INTERVAL 30 minute);
update tab_test state=1064,time=now() where id in(......);
至此MySQL死锁问题得以解决!


猜你喜欢
- 本文实例分析了Python中的对象,方法,类,实例,函数用法。分享给大家供大家参考。具体分析如下:Python是一个完全面向对象的语言。不仅
- 如下所示:#coding utf-8a=0.001 #定义收敛步长xd=1 #定义寻找步
- Pyplotmatplotlib.pyplot是一个命令型函数集合,它可以让我们像使用MATLAB一样使用matplotlib。pyplot
- 随着3G的普及,越来越多的人使用手机上网。移动设备正超过桌面设备,成为访问互联网的最常见终端。于是,网页设计师不得不面对一个难题:如何才能在
- 简单的Tensorflow验证码识别应用,供大家参考,具体内容如下1.Tensorflow的安装方式简单,在此就不赘述了.2.训练集训练集以
- 回车和换行的历史:机械打字机有回车和换行两个键作用分别是:换行就是把滚筒卷一格,不改变水平位置。 (即移到下一行,但不是行首,而是和上一行水
- 前段时间写了一个百度图片下载器,结果发现有很多人需要使用。说实话之前写的那一款百度图片下载器比较LOW,今天刚好有时间就做了一下升级。更新了
- 通常情况下,当我们要生成一个随机字符串时,总是先创建一个字符池,然后用一个循环和mt_rand()或rand()生成php随机数,从字符池中
- 一、环境介绍操作系统: win10 64位python版本: 3.8IDE: 采用vscode用到的相关安装包CSDN打包下载地址: htt
- 为了UED前端团队更好的协作开发同时提高项目编码质量,我们需要将Web前端使用工程化方式构建;目前需要一些简单的功能:  
- 场景:主库DB:utf8字符集备库DB:gbk字符集需求:校验主备数据是否一致,并且修复校验过程:设置主库连接为utf8,设置备库连接为gb
- 目录1. 前言2. Echarts3. Pyecharts3-1 安装依赖3-2 拷贝 
- 在做项目时发现,很多场合都可能用到Input但又想让它具有select的特性,研究了一下,似乎可以实现,下面的代码可以大概说明我的意图,但实
- 问题重现Installing golang.org/x/tools/cmd/guru FAILED Installing golang.or
- 本文实例讲述了Python中文分词实现方法。分享给大家供大家参考,具体如下:在Python这pymmseg-cpp 还是十分方便的!环境 u
- matplotlib制作简单的动画动画即是在一段时间内快速连续的重新绘制图像的过程.matplotlib提供了方法用于处理简单动画的绘制:i
- 1 使用Flask处理表单什么是表单(Form)? 表单是搜集用户数据信息的各种表单元素的集合区域。它的作用是实现用户和服务器的数据交互。通
- 一、模块&包简介模块:所谓模块就是一个.py文件,用来存放变量,方法的文件,便于在其他python文件中导入(通过import或fr
- 一、使用dotnet add package 命令行实现首先可以去这个网站:https://www.nuget.org/ 查找想要添加的引用
- 前言了解 Python 的都知道 Pyinstaller 可以将 .py 文件打包成 windows 下可执行的 .exe 文件, 但是在我