当前位置: 首页 > 编程笔记 >

InnoDB数据库死锁问题处理

籍昱
2023-03-14
本文向大家介绍InnoDB数据库死锁问题处理,包括了InnoDB数据库死锁问题处理的使用技巧和注意事项,需要的朋友参考一下

场景描述

在update表的时候出现DeadlockLoserDataAccessException异常 (Deadlock found when trying to get lock; try restarting transaction...)。

问题分析

这个异常并不会影响用户使用,因为数据库遇到死锁会自动回滚并重试。用户的感觉就是操作稍有卡顿。但是监控老是报异常,所以需要解决一下。

解决方法

在应用程序中update的地方使用try-catch。

我自己封装了一个函数,如下。

/**
   * 2016-03-15
   * linxuan
   * handle deadlock while update table
   */
  private void updateWithDeadLock(TestMapper mapper, Test record) throws InterruptedException {
    boolean oops;
    int retries = 5;
    do{
      oops = false;
      try{
        mapper.updateByPrimaryKeySelective(record);
      }
      catch (DeadlockLoserDataAccessException dlEx){
        oops = true;
        Thread.sleep((long) (Math.random() * 500));
      }
      finally {
      }
    } while(oops == true && retries-- >0);
  }

我用的是mybatis,所以只需将mapper传进函数,如果不用mybatis,需要自己创建并关闭数据库连接。

延伸:数据库死锁

数据库死锁是事务性数据库 (如SQL Server, MySql等)经常遇到的问题。除非数据库死锁问题频繁出现导致用户无法操作,一般情况下数据库死锁问题不严重。在应用程序中进行try-catch就可以。那么数据死锁是如何产生的呢?

InnoDB实现的是行锁 (row level lock),分为共享锁 (S) 和 互斥锁 (X)。

共享锁用于事务read一行。
互斥锁用于事务update或delete一行。
当客户A持有共享锁S,并请求互斥锁X;同时客户B持有互斥锁X,并请求共享锁S。以上情况,会发生数据库死锁。如果还不够清楚,请看下面的例子。

数据库死锁例子

首先,客户A创建一个表T,并向T中插入一条数据,客户A开始一个select事务,所以拿着共享锁S。

mysql> CREATE TABLE t (i INT) ENGINE = InnoDB;
Query OK, 0 rows affected (1.07 sec)

mysql> INSERT INTO t (i) VALUES(1);
Query OK, 1 row affected (0.09 sec)

mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT * FROM t WHERE i = 1 LOCK IN SHARE MODE;
+------+
| i  |
+------+
|  1 |
+------+

然后,客户B开始一个新事务,新事务是delete表T中的唯一一条数据。

mysql> START TRANSACTION;
Query OK, 0 rows affected (0.00 sec)

mysql> DELETE FROM t WHERE i = 1;

删除操作需要互斥锁 (X),但是互斥锁X和共享锁S是不能相容的。所以删除事务被放到锁请求队列中,客户B阻塞。

最后,客户A也想删除表T中的那条数据:

mysql> DELETE FROM t WHERE i = 1;
ERROR 1213 (40001): Deadlock found when trying to get lock;
try restarting transaction

死锁产生了!因为客户A需要锁X来删除行,而客户B拿着锁X并正在等待客户A释放锁S。看看客户A,B的状态:

客户A: 拿着锁S,等待着客户B释放锁X。
客户B: 拿着锁X,等待着客户A释放锁S。

发生死锁后,InnoDB会为对一个客户产生错误信息并释放锁。返回给客户的信息:

ERROR 1213 (40001): Deadlock found when trying to get lock;
try restarting transaction
所以,另一个客户可以正常执行任务。死锁结束。

 类似资料:
  • 问题内容: 谁能解释一下为什么这段代码中会出现死锁。 问题答案: 这可能是如何执行的。 输入,由于关键字已锁定Alphonse 输入,加斯顿现已锁定 无法通过第一个方法调用执行,因为加斯顿(鲍尔)被锁定。等待锁被释放。 由于alphonse(上弦器)已锁定,因此无法从第二个方法调用执行。等待锁被释放。 两个线程都互相等待释放锁。

  • 本文向大家介绍详解MySQL(InnoDB)是如何处理死锁的,包括了详解MySQL(InnoDB)是如何处理死锁的的使用技巧和注意事项,需要的朋友参考一下 一、什么是死锁 官方定义如下:两个事务都持有对方需要的锁,并且在等待对方释放,并且双方都不会释放自己的锁。 这个就好比你有一个人质,对方有一个人质,你们俩去谈判说换人。你让对面放人,对面让你放人。 二、为什么会形成死锁 看到这里,也许你会有这样

  • 问题内容: 某些数据库功能(例如和)很容易受到死锁的影响,因为数据库未指定将使用哪种锁定顺序。我发现有两次 讨论暗示此行为不是SQL标准指定的,更不用说具体的实现了。因此,我在假设我们无法控制锁定顺序的情况下进行操作(至少,这样做并不明显)。 如果我们不能依赖锁定顺序,应该如何避免数据库死锁? 如果我们不应该避免僵局(您将不得不非常努力地说服我),那么我们应该怎么做? 这个问题与数据库无关,所以请

  • 本文向大家介绍MySQL中InnoDB的间隙锁问题,包括了MySQL中InnoDB的间隙锁问题的使用技巧和注意事项,需要的朋友参考一下  在为一个客户排除死锁问题时我遇到了一个有趣的包括InnoDB间隙锁的情形。对于一个WHERE子句不匹配任何行的非插入的写操作中,我预期事务应该不会有锁,但我错了。让我们看一下这张表及示例UPDATE。   InnoDB状态显示这个UPDATE在主索引记录上持有了

  • 我使用Spring-Data-Jpa并使用@Lock注释(悲观_写)来获取数据库(Oracle)锁。我需要帮助来了解以下场景是否会导致数据库死锁。 事务1(PROPAGATION_REQUIRES_NEW,ISOLATION_DEFAULT)将数据库锁定在say教师表上(说锁定在id=1的行上)。它试图在子表中插入一条新记录,比如会议。教师表没有更新 当事务1正在进行时。事务2(PROPAGATI

  • seata版本:1.4.0,但1.4以下的所有版本也都有这个问题 问题描述:在一个全局事务中,一个分支事务上的纯查询操作突然卡住了,没有任何反馈(日志/异常),直到消费端RPC超时 问题排查 整个流程在一个全局事务中,消费者和提供者可以看成是全局事务中的两个分支事务,消费者 --> 提供者 消费者先执行本地的一些逻辑,然后向提供者发送RPC请求,确定消费者发出了请求已经并且提供者接到了请求 提供者