• 技术文章 >数据库 >mysql教程

    InnoDB数据库死锁问题处理_MySQL

    PHP中文网PHP中文网2016-05-27 13:45:15原创612
    InnoDB数据库死锁问题处理_MySQL

    场景描述

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

    以上就是InnoDB数据库死锁问题处理_MySQL的内容,更多相关内容请关注PHP中文网(m.sbmmt.com)!

    声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn核实处理。
    上一篇:查看和修改MySQL数据库表存储引擎_MySQL 下一篇:安装解压版Mysql方法_MySQL
    千万级数据并发解决方案

    相关文章推荐

    • MySQL学习之DDL、DML及DQL基础总结• mysql中where查询语句怎么用• mysql怎样只导出表结构• mysql怎么查询所有表及注释• mysql怎么去掉第一个字符
    1/1

    PHP中文网