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创建一个表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

所以,另一个客户可以正常执行任务。死锁结束。

(完)

时间: 2024-10-18 09:25:44

InnoDB数据库死锁的相关文章

Mybatis-update - 数据库死锁 - 获取数据库连接池等待

最近学习测试mybatis,单个增删改查都没问题,最后使用mvn test的时候发现了几个问题: update失败,原因是数据库死锁 select等待,原因是connection连接池被用光了,需要等待 get: 要勇于探索,坚持就是胜利.刚看到错误的时候直接懵逼,因为错误完全看不出来,属于框架内部报错,在犹豫是不是直接睡觉得了,毕竟也快12点了.最后还是给我一点点找到问题所在了. 同上,要敢于去深入你不了解的代码,敢于研究不懂的代码. 距离一个合格的码农越来越远了,因为越学越觉得漏洞百出,自己

数据库死锁

最近做项目时,将原先单条插入更新数据库时改为批量插入更新.这样做的好处是降低了QPS(sql语句的数量),但是同时也带来一个问题,DB的行锁急剧增加. 由于批量更新执行时间长,导致资源被长时间锁定,从而导致了大量的死锁产生,即出现以下错误信息: Deadlock found when trying to get lock; try restarting transaction 借这个机会,研究一下数据库死锁的问题. 一. 什么是数据库死锁? 学过操作系统的人都知道,只有在并发的情况下,才会发生死

mysql数据库死锁

当我们频繁的对数据库进行插入或更新的时候,有可能会直接报sql错误1205:lock wait timeout exceeded.数据库的死锁. 一般INNODB数据库会自动添加事务,当进行插入或者更新的时候,如果上次commit尚未执行完,而又有一次新的commit提交的时候,系统就会报SQL错误1205:lock wait timeout exceeded.这就是mysql死锁. 作为一个新手,碰到这样苦逼的事情自然是手足无措.于是赶紧上网看看解决方案,不负所望,网上还真找到相应的结局方案,

记一次数据库死锁

业务新上了一个功能,在发布的过程中,系统报出了数据库死锁异常: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction 死锁发生在一个事务中,事务对多个表进行了操作.在报错日志中,死锁发生在tableA与tableB.一开始怀疑此次发布的某个改动中对上面这两张表新增了select或upd

MySQL数据库死锁分析

背景说明: 公司内部一套自建分布式交易服务平台,在POC稳定性压力测试的时候出现了数据库死锁.(InnoDB引擎)由于保密性,假设是app_test表死锁了. 现象: 发生异常:Deadlock found when trying to get lock; try restarting transaction 分析思路: 1.回忆和查找相关资料,InnoDB死锁导致的原因. 第一:涉及多表访问,两个事务相互占有对方需要的锁.假设有A表(含有初始化记录1)和B表(含有初始化记录2).进行如下操作会

SqlServer定时备份数据库和定时杀死数据库死锁解决

PS:Sqlserver 2008 R2,windows 8 64位 1.备份数据库 因为要备份,我们就要用到Sqlserver的代理,默认数据库的代理是不开启的.需要我们手动开启的. 执行备份数据库脚本,现在将脚本公布,其实将这一段代码中需要保存的文件路径和数据库名称替换一下就可以实现备份了.但是还没有达到定时备份的目的 ? 1 2 3 4 5 6 7 8 9 10 11 --自动备份并保存最近5天的SQL数据库作业脚本 宋彪 20130310 DECLARE @filename VARCHA

mysql5.7 innodb数据库备份工具Xtrabackup的安装

mysql5.7 innodb数据库备份工具Xtrabackup的安装     wget mhttps://www.percona.com/downloads/XtraBackup/Percona-XtraBackup-2.4.7/binary/redhat/6/x86_64/percona-xtrabackup-24-2.4.7-1.el6.x86_64.rpm Mysql5.7需要安装XtraBackup 2.4.1以上版本 官网地址 https://www.percona.com/down

nagios 添加自定义监控项目监控mysql数据库死锁

nagios 添加自定义监控项目 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 系统环境:CentOS Linux release 7.2.1511 (Core) nagios 版本: 2.15 这里配合pt-dead-logger插件了,运行了这个插件,有死锁就会在test.deadlocks表写入死锁的信息 这里通过检测这个表是否增加了行数来发报警 nagios客户端自定义脚本: ###这里为了省事,直接把数据库的用户,

关于数据库死锁的检查方法

关于数据库死锁的检查方法 一.        数据库死锁的现象程序在执行的过程中,点击确定或保存按钮,程序没有响应,也没有出现报错. 二.        死锁的原理当对于数据库某个表的某一列做更新或删除等操作,执行完毕后该条语句不提交,另一条对于这一列数据做更新操作的语句在执行的时候就会处于等待状态,此时的现象是这条语句一直在执行,但一直没有执行成功,也没有报错. 三.        死锁的定位方法通过检查数据库表,能够检查出是哪一条语句被死锁,产生死锁的机器是哪一台.1)用dba用户执行以下语