如何解决生产环境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

相关推荐

  • Mysql5.5中文乱码问题

    查看MySQL的字符集 发现有部分不是utf-8 一(推荐,本人实验有用) 修改MySQL配置文件,来到mysql安装目录,找到my.ini文件(可能没有此文件,没有就自己建一个,本人就是没有该文件) 若有my.ini文件 进去之后,在三个地方增加配置 第一个 第二个 第三个 若没有my.ini文件,则添加一个,内容为: 注意!!! 记得重启mysql服务 …

    2022年8月21日
    43500
  • root用户无法访问Mysql数据库问题的解决

    在使用Centos系统远程访问Mysql数据库的时候,系统提示报如下错误: 经过验证以下方案可以解决问题: 1.首先停止mysql服务器 2.无权限启动mysql服务 3..登录mysql 4..重新载入权限 5.. 选择系统数据库mysql 6..查询系统表user中的用户 7.向root用户赋值权限

    2023年6月20日
    21500
  • count(1)、count(*)与count(列名)的执行区别

    在工作中遇到count(*)、count(1)、count(col) ,可能会让你分不清楚,都是计数,干嘛这么搞这么多东西。 count 作用 COUNT(expression):返回查询的记录总数,expression 参数是一个字段或者 * 号。 测试 MySQL版本:5.7.29 创建一张用户表,并插入一百万条数据,其中gender字段有五十万行是为n…

    2023年1月12日
    37600
  • Redis 常用命令

    一、redis启动: Redis 连接命令 二、redis keys命令 三、reids字符串命令 四、Redis hash 命令 五、Redis 列表命令 六、Redis 集合命令 七、Redis 有序集合命令 八、Redis 发布订阅命令 九、Redis 事务命令 十、Redis 脚本命令 十一、Redis 服务器命令

    2022年7月29日
    38200
  • 如何快速实现 Redis 持久化

    RDB快照(Redis DataBase) RDB是一种快照存储持久化方式,具体就是将Redis某一时刻的内存数据保存到硬盘的文件当中,默认保存的文件名为dump.rdb,而在Redis服务器启动时,会重新加载dump.rdb文件的数据到内存当中恢复数据。 开启RDB持久化方式 开启RDB持久化方式很简单,客户端可以通过向Redis服务器发送save或bgs…

    2023年6月29日
    19600

发表回复

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

在线咨询: QQ交谈

邮件:712342017@qq.com

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

关注微信