MySQL死锁使用详解及检测和避免方法
作者:向着百万年薪努力的小赵 发布时间:2024-01-24 04:44:48
前言
上一篇博客我们知道的Mysql事务的隔离机制和实现,以及锁的详细解析
链接: MySQL脏读幻读不可重复读及事务的隔离级别和MVCC、LBCC实现
在我们使用锁的时候,有一个问题是需要注意和避免的,我们知道,排它锁有互斥的特性。一个事务或者说一个线程持有锁的时候,会阻止其他的线程获取锁,这个时候会造成阻塞等待,如果循环等待,会有可能造成死锁。
这个问题我们需要从几个方面来分析,一个是锁为什么不释放,第二个是被阻塞了怎么办,第三个死锁是怎么发生的,怎么避免。
锁的释放与阻塞
回顾:锁什么时候释放?
事务结束(commit,rollback)﹔
客户端连接断开。
如果一个事务一直未释放锁,其他事务会被阻塞多久?会不会永远等待下去?
如果是,在并发访问比较高的情况下,如果大量事务因无法立即获得所需的锁而挂起,会占用大量计算机资源,造成严重性能问题,甚至拖跨数据库。
线上怕不怕这个错?
[Err] 1205 - Lock wait timeout exceeded; try restarting transaction
MySQL有一个参数来控制获取锁的等待时间,默认是50秒。
show VARIABLES like "innodb_lock_wait_timeout";
对于死锁,是无论等多久都不能获取到锁的,这种情况,也需要等待50秒钟吗?那不是白白浪费了50秒钟的时间吗?
死锁的发生和检测
演示一下,开两个会话:
方便对时间线的提现,这里用图片,有兴趣的可以跟着模仿一下
栗子一:
栗子二:
在第一个事务中,检测到了死锁,马上退出了,第二个事务获得了锁,不需要等待50秒:
[Err] 1213 - Deadlock found when trying to get lock; try restarting transaction
为什么可以直接检测到呢?是因为死锁的发生需要满足一定的条件,对于我们程序员来说,有明确的条件,意味着能判定,所以在发生死锁时,InnoDB一般都能通过算法(wait-for graph)自动检测到。
那么死锁需要满足什么条件?死锁的产生条件,因为锁本身是互斥的:
(1)同一时刻只能有一个事务持有这把锁;
(2)其他的事务需要在这个事务释放锁之后才能获取锁,而不可以强行剥夺;
(3)当多个事务形成等待环路的时候,即发生死锁。
理发店有两个总监。一个负责剪头的Tony老师,一个负责洗头的Kelvin老师。Tony老师不能同时给两个人剪头,这个就叫互斥
。
Tony在给别人在剪头的时候,你不能让他停下来帮你剪头,这个叫不能强行剥夺
。
如果Tony的客户对Kelvin说:你不帮我洗头我怎么剪头? Kelvin 的客户对Tony说:你不帮我剪头我怎么洗头?这个就叫形成等待环路
。
实际上,发生死锁的情况非常多,但是都满足以上3个条件。
这个也是表锁是不会发生死锁的原因,因为表锁的资源都是一次性获取的。
如果锁一直没有释放,就有可能造成大量阻塞或者发生死锁,造成系统吞吐量下降,这时候就要查看是哪些事务持有了锁。
查看锁信息(日志)
首先,SHow STATUS命令中,包括了一些行锁的信息:
show status like 'innodb_row_lock_%';
lnnodb_row_lock_current_waits:当前正在等待锁定的数量;
lnnodb_row_lock_time :从系统启动到现在锁定的总时间长度,单位ms;
Innodb_row_lock_time_avg :每次等待所花平均时间;
Innodb_row_lock_time_max:从系统启动到现在等待最长的一次所花的时间;
lnnodb_row_lock_waits :从系统启动到现在总共等待的次数。
SHOW命令是一个概要信息。InnoDB还提供了三张表来分析事务与锁的情况:
select * from information_schema.INNODB_TRX; --当前运行的所有事务﹐还有具体的语句
select* from information_schema.INNODB_LOCKS; --当前出现的锁
select * from information_schema.INNODB_LOCK_WAITS; --锁等待的对应关系
更加详细的锁信息,开启标准监控和锁监控:
额外的监控肯定会消耗额外的性能
set GLOBAL innodb_status_output=ON;
set GLOBAL innodb_status_output_locks=ON;
通过分析锁日志,找出持有锁的事务之后呢?
如果一个事务长时间持有锁不释放,可以kill事务对应的线程ID,也就是INNODB_TRX表中的trx_mysql_thread_id,例如执行kill 4,kill 7, kill 8。
当然,死锁的问题不能每次都靠kill线程来解决,这是治标不治本的行为。我们应该尽量在应用端,也就是在编码的过程中避免。
有哪些可以避免死锁的方法呢?
死锁的避免
1、在程序中,操作多张表时,尽量以相同的顺序来访问(避免形成等待环路)
2、批量操作单张表数据的时候,先对数据进行排序(避免形成等待环路);
3、申请足够级别的锁,如果要操作数据,就申请排它锁;
4、尽量使用索引访问数据,避免没有where条件的操作,避免锁表;
5、如果可以,大事务化成小事务;
6、使用等值查询而不是范围查询查询数据,命中记录,避免间隙锁对并发的影响。
来源:https://blog.csdn.net/weixin_44688973/article/details/125563264


猜你喜欢
- 本文介绍了mint-ui在vue中的使用示例,分享给大家,具体如下:首先放上 mint-ui中文文档近来在使用mint-ui,发现部分插件在
- 一、Go语言通道基础概念1.channel产生背景 线程之间进行通信的时候,会因为资源的争夺而产生竟态问
- 在Unix和NetWare中推荐使用mysqld_safe来启动mysqld服务器。mysqld_safe增加了一些安全特性,例如当出现错误
- 很久之前用到的,现在整理在这,里面一些代码来源于网上,不过有些bug已被我修改了。1.查询结果转XMLDECLARE @ParameterS
- 1.什么是Store?上一篇文章说了,Vuex就是提供一个仓库,Store仓库里面放了很多对象。其中state就是数据源存放地,对应于与一般
- 一、前言该测试功能是Linux产测软件的一个子功能,主要涉及:140行代码PySide2的Event、信号和槽、QLabel,QWidget
- 0x 00 返回值简介回顾下,上一节简单介绍了函数及其各种参数,其中也有简单介绍 print 和 return 的区别,print 仅仅是打
- mysql在5.1之后增加了存储过程的功能, 存储过程运行在mysql内部,语句都已经编译好了,速度比sql更快. 存储过程与mysql相当
- 实例如下:<?php /** * @name thumb 缩略图函数 * @param sting  
- 本文章以一个表为例,要转多个表则可将DataSet关联多个表,下面给出完整代码,包括引用以及main函数与复制函数。要说明的是,必须先用Sq
- 嗯,开场先胡扯几句不相关地感言。最近的工作让我有了很多实践的机会,同时也让我收获颇丰。在群里聊天的时候也提到过,所有的学习过程,最好是理论-
- 目录文件读写读文件写文件StringIO和BytesIOStringIOBytesIO操作文件和目录环境变量操作文件和目录文件读写读文件tr
- Django的核心(1.4+)可以运行在从2.5到2.7之间的任何Python版本。我的电脑是操作系统是window10 ,内存是4G。1。
- 暂时是一个手动设置无向图中的边,用一个二维数组表示,后面会改进为用户自己定义无向图的边。学习python的新手,若大佬有解决的办法,希望不吝
- 概述:本控件使用 html+css+javascript模拟HTML内置的select元素,实现其部分方法与属性,也增加了一部分功能,并且从
- 最近用python的正则表达式处理了一些文本数据,需要把结果写到文件里面,但是由于文件比较大,所以运行起来花费的时间很长。但是打开任务管理器
- 英文文档:eval(expression, globals=None, locals=None)The arguments are a st
- 华为2019在线笔试题,现整理如下,以供之后参考GitHub题目介绍####################################
- 今天在写一个linux下自动备份指定目录下的所有目录的脚本时,遇到了一个问题,由于我是需要备份目录,所以,需要判断扫描的文件是否为目录,当我
- requests相比urllib,第三方库requests更加简单人性化,是爬虫工作中常用的库requests安装初级爬虫的开始主要是使用r