在分析案例之前,我们先了解一下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 数据库死锁问题的更多相关文章

  1. mysql数据库死锁的产生原因及解决办法

    这篇文章主要介绍了mysql数据库锁的产生原因及解决办法,需要的朋友可以参考下   数据库和操作系统一样,是一个多用户使用的共享资源.当多个用户并发地存取数据 时,在数据库中就会产生多个事务同时存取同 ...

  2. MySQL 数据库死锁

    数据库死锁 死锁的解决办法(1) 执行下面SQL,先查看哪些表被锁住了: select b.owner,b.object_name,a.session_id,a.locked_mode from v$ ...

  3. MySQL数据库死锁分析

    背景说明: 公司内部一套自建分布式交易服务平台,在POC稳定性压力测试的时候出现了数据库死锁.(InnoDB引擎)由于保密性,假设是app_test表死锁了. 现象: 发生异常:Deadlock fo ...

  4. 记一次线上MySQL数据库死锁问题

            最近线上项目报了一个MySQL死锁(DealLock)错误,虽说对业务上是没有什么影响的,由于自己对数据库锁这块了解不是很多,之前也没怎么的在线上碰到过.这次刚好遇到了,便在此记录一下 ...

  5. Mysql数据库死锁分析相关概念

    参考博客: mysql死锁问题分析(https://www.cnblogs.com/LBSer/p/5183300.html) mysql insert锁机制(http://yeshaoting.cn ...

  6. 关于在项目中遇到MySQL数据库死锁的问题

    在MySQL中, 当一个事务去更新某条数据, 还没有提交的时候, 第二个事务去更新该数据, 则会出现等待获取锁超时异常: >> Lock wait timeout exceeded; tr ...

  7. mysql数据库死锁的解决方案

    1. 查询锁表信息    show OPEN TABLES where In_use > 0;2. 查看当前数据库锁表的情况    SELECT * FROM information_schem ...

  8. Mybatis-update - 数据库死锁 - 获取数据库连接池等待

    最近学习测试mybatis,单个增删改查都没问题,最后使用mvn test的时候发现了几个问题: update失败,原因是数据库死锁 select等待,原因是connection连接池被用光了,需要等 ...

  9. MySQL 性能优化-数据库死锁监控

    MySQL性能优化-数据库死锁监控 by:授客 QQ:1033553122 1)表锁定 通过检查 table_locks_waited 和 table_locks_immediate 状态变量来分析表 ...

  10. 一个项目中mysql数据库经常死锁的问题解决记录

    1.问题描述 此项目为一个物流系统,需要使用PDA对货物进行入库.备货.出货等操作,在系统开发测试过程中,经常发现死锁问题. 有这样一种业务场景:仓库对备货单上货进行扫码备货后,点击"完成& ...

随机推荐

  1. 24 Django模块的导入--常用总结

    常用模块导入 1 forms # forms组件的使用 from django import forms 2 ValidationError # modelform报错时使用 from django. ...

  2. SQL查询 错误 [1843] [22008]: ORA-01843: 无效的月份

    dbeaver客户端运行sql查询Oracle库报错. 正确示例: select count(*) from PRODUCTS WHERE CREATE_TIME > '15-7月-2021 ' ...

  3. opencv实战之透视变换

    import cv2 import numpy as np import pytesseract def cv_show(imgname,img): cv2.imshow(imgname,img) c ...

  4. 给linux串口,增加登录密码

    一.密码更改 1.在linux系统上,输入passwd,输入需要设定的密码,密码文件保存在/etc/passwd里面. 2.把/etc/passwd文件拷贝出来,放到rootfs的etc/目录下,实现 ...

  5. java 操作excel

    需要引入的包 import org.apache.poi.hssf.usermodel.*; import org.apache.poi.ss.usermodel.HorizontalAlignmen ...

  6. Merge Overlapping Intervals

    refer to: https://www.algoexpert.io/questions/Merge%20Overlapping%20Intervals Problem Statement Samp ...

  7. UI自动化之【maven+selenium环境搭建】

    一.下载maven包 官网: http://maven.apache.org/download.cgi 二.配置maven环境变量  配置完之后验证一下:(若出现以下信息可看到maven的版本号就表示 ...

  8. vue多图片上传组件

    <template> <!-- 上传控件 用法: <upload-widget v-model="imgUrl"></upload-widget ...

  9. javascript数据类型,定义方法,(工厂模式及闭包的应用)

    js数据类型分为两大类:一  值类型                                        二 引用类型 一 值类型  string  number  boolean null ...

  10. Crypto入门 (七) Railfence (栏栅密码,正常型和W型)

    前言: Crypto中分三类,分别是编码.古典密码.现代密码,栏栅密码属于古典密码中得特殊移位密码,密钥只有 一个k,表示栏栅得长度.所谓栏栅密码就是将要加密得明文分成k个一组,然后取每组得第一个字符 ...