如何解决生产环境MySQL的死锁问题

生产问题

在生产环境中发现我们数据库出现了一个异常,异常堆栈信息如下:

Error updating database. 
Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException:
Deadlock found when trying to get lock; try restarting transaction\n### The error may involve
xxxMapper.updateByExampleSelective-Inline\n### The error occurred while setting parameters\n###
SQL: UPDATE xxx  SET to_recipient_id = ?,logistics_order_id = ?,delivery_type = ?,delivery_no = ?,
delivery_company_code = ?,delivery_big_pen = ?,delivery_package_site_name = ?,delivery_extended_attribute = ?,
delivery_label_url = ?,customs_channel_code = ?,declare_no = ?,create_time = ?,update_time = ?,delete_flag = ?,
channel_hawb_code = ?,system_order_code = ?,change_sign = ?,delivery_extended_no = ?,delivery_child_no = ?
WHERE (       (  logistics_order_id = ? ) )

从堆栈信息可以很容易知道死锁问题。但是这个更新语句为什么会出现死锁呢?

问题原因

死锁产生的原因有四个分别是:

  • 互斥
  • 循环等待
  • 不可剥夺
  • 请求与保持

只要产生死锁以上四个条件比然满足,因此考虑这个SQL语句是否产生了这四个死锁条件。

分析:

由于我们使用的是云数据库,因此可以通过云数据库控制台查看锁分析,分析结果如下:

如何解决生产环境MySQL的死锁问题

可以看到死锁的产生是由于两个事务互相竞争导致的,那么两个事务如何产生死锁呢?

两个事务产生死锁的条件如下:

事务1: lock A, then B 事务2: lock B, then A

翻译一下就是:

事务1

update table 1 set name = 1 where id = 1;

update table2 set age = 2 where id = 3;

事务2

update table2 set age = 2 where id = 3;

update table 1 set name = 1 where id = 1;

即两个事务中,T1 锁定了A,要去获取B的资源锁,但是T2已经锁定了资源B,T2要去获取A的锁,两个都不释放,从而导致死锁。

根据这种场景分析生产执行SQL找到了对应的SQL问题,问题的原因也是前面描述的一样,两个事务互相竞争等待导致的。

解决方案

那么针对这种情况如何解决呢?

方案1:两个事务的执行SQL改成一样,即

事务1

update table 1 set name = 1 where id = 1;

update table2 set age = 2 where id = 3;

事务2

update table 1 set name = 1 where id = 1;

update table2 set age = 2 where id = 3;

按照相同的顺序执行SQL,即使出现并发情况,那么行锁也会等待而不会死锁。

方案2:提取事务,将不必要的SQL不加入事务中

事务1

update table 1 set name = 1 where id = 1;

commit;

update table2 set age = 2 where id = 3;

通过分析将不必要的SQL从事务中提取。

文章来源:https://www.cnaaa.net,转载请注明出处:https://www.cnaaa.net/archives/5958

(0)
安屠生的头像安屠生
上一篇 2022年8月21日 下午1:35
下一篇 2022年8月21日 下午1:45

相关推荐

  • 内存耗尽后Redis会发生什么

    前言 作为一台服务器来说,内存并不是无限的,所以总会存在内存耗尽的情况,那么当 Redis 服务器的内存耗尽后,如果继续执行请求命令,Redis 会如何处理呢? 内存回收 使用Redis 服务时,很多情况下某些键值对只会在特定的时间内有效,为了防止这种类型的数据一直占有内存,我们可以给键值对设置有效期。Redis 中可以通过 4 个独立的命令来给一个键设置过…

    2023年7月17日
    80000
  • Sql Server数据库显示中文乱码的解决方案

    .数据库中文乱码原因 1. 一种情况是实际生产环境的电脑并不支持中文语言,但是数据库的数据表里面,有些说明字段需要用中文显示,这个时候就出现了乱码了 2. 另外一种情况是,安装数据库的时候,使用的是默认的编码规则。这个时候如果电脑本身就不支持中文语言。然后数据库表里面录入中文,也会出现乱码。支持中文的电脑,安装使用默认的选项,数据表录入中文,好像没有出现过乱…

    2023年2月18日
    1.1K00
  • 数据库报错:Cause com.mysql.jdbc.exceptions.jdbc4.CommunicationsException:Communications link failure

    原因1.因为SSL连接原因(大部分人的原因)因为MySQL在高版本需要指明是否进行SSL连接。有可能你 pom 文件引入的 MySQL 依赖版本是MySQL5.7及以上 这些的时候,你就需要指定SSL连接,如果你不知道,默认就是开启,所以就会出现上面的错误。 2.因为数据库连接超时原因当数据库重启或数据库空闲连接超过设置的最大timemout时间,数据库会强…

    2023年8月1日
    88200
  • MySQL InnoDB调试死锁

    前提 1、在RR隔离级别下。2、查看间隙锁是否关闭区间锁(间隙锁,临键锁)是InnoDB特有施加在索引记录区间的锁,MySQL5.6可以手动关闭区间锁,它由innodb_locks_unsafe_for_binlog参数控制: show global variables like “innodb_locks%”; 3、show glo…

    2023年10月23日
    1.3K00
  • MySQL数据库主从的安装搭建方法

    环境准备 准备两台虚拟机或者云服务器,作为数据库的主节点和从节点 ​ 第一步  修改主机名host并配置主机映射 将两台主机分别修改为mysql1和mysql2,修改命令如下: 两个节点配置/etc/hosts文件,修改为如下: #ip地址应改成自己主机对应的ip 第二步   两台主机都关闭防火墙和SELinux服务 …

    2022年6月8日
    3.2K10

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

在线咨询: QQ交谈

邮件:712342017@qq.com

工作时间:周一至周五,8:30-17:30,节假日休息

关注微信