MySQL 数据库死锁问题
在分析案例之前,我们先了解一下MySQL INNODB。在MySQL INNODB引擎中主键是采用聚簇索引的形式,即在B树的叶子节点中既存储了索引值也存储了数据记录,即数据记录和主键索引是存在一起的。而普通索引的叶子节点存储的只是主键索引的值,一次查询找到普通索引的叶子节点后,还要根据叶子节点中的主键索引去找到聚簇索引叶子节点并拿到其中的具体数据记录,这个过程也叫“回表”。
故障发生的场景是关于我们商城的订单系统。有一个定时任务,每一小时跑一次,每次把所有一小时前未支付订单取消掉。而客服后台也可以批量取消订单。订单表 t_order结构大至如下:
|
id |
订单id,主键 |
|
status |
订单状态 |
|
created_time |
订单创建时间 |
id是表的主键,created_time字段上是普通索引。
聚簇索引(主键id)
|
id(索引) |
status |
created_time |
|
1 |
UNPAID |
2020-01-01 07:30:00 |
|
2 |
UNPAID |
2020-01-01 08:33:00 |
|
3 |
UNPAID |
2020-01-01 09:30:00 |
|
4 |
UNPAID |
2020-01-01 09:39:00 |
|
5 |
UNPAID |
2020-01-01 09:50:00 |
普通索引(created_time字段)
|
created_time(索引) |
id(主键) |
|
2020-01-01 09:50:00 |
5 |
|
2020-01-01 09:39:00 |
4 |
|
2020-01-01 09:30:00 |
3 |
|
2020-01-01 08:33:00 |
2 |
|
2020-01-01 07:30:00 |
1 |
定时任务每一小时跑一次,每次把所有一小时前两小时内的未支付订单取消掉,比如上午11点会取消8点到10点的未支付订单。SQL语句如下:
update t_order set status = 'CANCELLED' where created_time > '2020-01-01 08:00:00' and created_time < '2020-01-01 10:00:00' and status = 'UNPAID'
客服批量取消订单SQL如下:
update t_order set status = 'CANCELLED' where id in (2, 3, 5) and status = 'UNPAID'
上面的两条语句同时执行就可能发生死锁。我们来分析一下原因。第一条定时任务的SQL,会先找到 created_time普通索引并加锁,然后再在找到主键索引并加锁。
第一步,created_time普通索引加锁
第二步,主键索引加锁
第二条客服批量取消订单SQL,直接走主键索引,直接在主键索引上加锁。
我们可以看到,定时任务 SQL对主键加锁顺序是5,4,3,2。客服批量取消订单 SQL对主键加锁顺序是2,3,5。当第一个 SQL对3加锁后,正准备对2加锁时,发现2已经被第二个SQL加锁了,所以第一个SQL要等待2的锁释放。而此时第二个SQL准备对3加锁,却发现3已经被第一个SQL加锁了,就要等待3的锁释放。两个SQL互相等待对方的锁,也就发生了“死锁”。
解决办法就是从SQL语句上保证加锁顺序一致。或者把客服批量取消订单 SQL改成每次 SQL操作只能取消一个订单,然后在程序里多次循环执行SQL,如果批量操作的订单数量不多,这种笨办法也是可行的。
MySQL 数据库死锁问题的更多相关文章
- mysql数据库死锁的产生原因及解决办法
这篇文章主要介绍了mysql数据库锁的产生原因及解决办法,需要的朋友可以参考下 数据库和操作系统一样,是一个多用户使用的共享资源.当多个用户并发地存取数据 时,在数据库中就会产生多个事务同时存取同 ...
- MySQL 数据库死锁
数据库死锁 死锁的解决办法(1) 执行下面SQL,先查看哪些表被锁住了: select b.owner,b.object_name,a.session_id,a.locked_mode from v$ ...
- MySQL数据库死锁分析
背景说明: 公司内部一套自建分布式交易服务平台,在POC稳定性压力测试的时候出现了数据库死锁.(InnoDB引擎)由于保密性,假设是app_test表死锁了. 现象: 发生异常:Deadlock fo ...
- 记一次线上MySQL数据库死锁问题
最近线上项目报了一个MySQL死锁(DealLock)错误,虽说对业务上是没有什么影响的,由于自己对数据库锁这块了解不是很多,之前也没怎么的在线上碰到过.这次刚好遇到了,便在此记录一下 ...
- Mysql数据库死锁分析相关概念
参考博客: mysql死锁问题分析(https://www.cnblogs.com/LBSer/p/5183300.html) mysql insert锁机制(http://yeshaoting.cn ...
- 关于在项目中遇到MySQL数据库死锁的问题
在MySQL中, 当一个事务去更新某条数据, 还没有提交的时候, 第二个事务去更新该数据, 则会出现等待获取锁超时异常: >> Lock wait timeout exceeded; tr ...
- mysql数据库死锁的解决方案
1. 查询锁表信息 show OPEN TABLES where In_use > 0;2. 查看当前数据库锁表的情况 SELECT * FROM information_schem ...
- Mybatis-update - 数据库死锁 - 获取数据库连接池等待
最近学习测试mybatis,单个增删改查都没问题,最后使用mvn test的时候发现了几个问题: update失败,原因是数据库死锁 select等待,原因是connection连接池被用光了,需要等 ...
- MySQL 性能优化-数据库死锁监控
MySQL性能优化-数据库死锁监控 by:授客 QQ:1033553122 1)表锁定 通过检查 table_locks_waited 和 table_locks_immediate 状态变量来分析表 ...
- 一个项目中mysql数据库经常死锁的问题解决记录
1.问题描述 此项目为一个物流系统,需要使用PDA对货物进行入库.备货.出货等操作,在系统开发测试过程中,经常发现死锁问题. 有这样一种业务场景:仓库对备货单上货进行扫码备货后,点击"完成& ...
随机推荐
- 使用Wireshark完成实验2-TCP
1.打开Google Chorme,进入https://gaia.cs.umass.edu/wireshark-labs/alice.txt 2.将文本保存,进入https://gaia.cs.uma ...
- 如何使用C++代码实现1-100之间的素数
#include "pch.h" #include <iostream> using namespace std; int main() { cout << ...
- 关于css选择器的一点点记录
<!-- 选择器: #id..class.标签.>子代. 后代.+紧跟一个.~紧跟所有.:(效果)伪类 --> <!-- 效果选择器常用属性: ...
- vue组件 子组件没有事件怎么 向父组件传递数据
通过ref去接收值!!! 需求图片 代码实现 //----------父组件 <div class="fingerprint-bottom"> <el-tabs ...
- centos7 硬盘扩容
参考 linux系统下,新加硬盘并把现有的/home目录扩容 最后加的容量在/目录 而不是在/home目录,而我本来把/home目录独立挂载在一个分区了 创建逻辑卷.可用使用命令 pvcreate / ...
- Oracle关联表进行修改操作(查询某个表,以某个表作为基础,修改其它表)
merge into tableA a using( SELECT a,b,c from tableB ) b on (a.id = b.id)//这里一定要用括号包起来.... when match ...
- 反序列化 sqlserver 中的 sysdiagrams,找到其中包含的表的信息
转载于:Script SQL Server 2005 diagrams to a file - CodeProject /** <summary> Based on ufn_Varbina ...
- 2023.1.21 app后端pyinstaller启动
1.打包后会在dist文件夹中暂时生成一个新的文件目录,点击app.exe后也是在这个暂时的文件目录下读取文件的,所以需要以下代码拷贝添加原始项目中的文件 pyinstaller -D app.py ...
- CF1272 B DIV3 ---代码对比
这次DIV3有点可惜啊,题解是我的与学长的代码对比 学长的原博客https://www.cnblogs.com/xyq0220/p/12036109.html B.Snow Walking Robot ...
- 【Unity】关于VS条件编译符号
写在前面 起因:我在回顾LuaFramework_UGUI(作者Jarjin Lee)代码时,看到了C#代码中的条件编译符号,比如下图的ASYNC_MODE.虽然字面上知道是什么意思,但我对VS的条件 ...