当前位置: 移动技术网 > IT编程>数据库>Mysql > InnoDB数据库死锁问题处理

InnoDB数据库死锁问题处理

2017年12月12日  | 移动技术网IT编程  | 我要评论

五丁目,唐代法曲典范,无轩之湮魄

场景描述

在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
所以,另一个客户可以正常执行任务。死锁结束。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网