一次Mysql下批量更新造成的死锁案例分析

  最近,公司现网的业务中出现上图所示的死锁异常,沿着问题分析,发现这个问题涉及很多数据库的基础知识。

背景:

  使用数据库:Mysql

  涉及表格:t_invest

  数据库隔离级别:可重复读(Repeatable Read)

  死锁场景:saveRepaymentInfo事务的A()方法对t_invest表执行如下update操作:

    <update id = "A" parameterType = "java.util.List">

      <foreach collecton = "list" item = "item" separator = ";">

        update t_invest

          set status = 1,

          end_date = #{item.endDate},

          period = #{item.periods},

          update_time = now()

          where invest_no = #{item.invest_no}

      </foreach>

      </update>

      invest_no字段为设置了唯一索引

异常信息:

死锁分析:

通过异常日志跟踪定位到业务代码,发现死锁出现在syncRedeemApply事务。

事务syncRedeemApply会进行t_invest表的status的批量更新,批次最大数量为1000条。t_invest表的事务隔离级别为“可重复读”,在该隔离级别下,每次执行更新操作时会对索引加行锁,这个事务不存在多线程并发访问的情况,推断不是因为多程序并发操作造成的死锁。

通过分析业务功能发现,其他分布式业务模块在saveRepaymentInfo事务进行t_invest表的status的批量更新的同时,另外有一个updateExitStatusByBatch事务同时也在invest表进行批量更新,而且都是利用investno索引进行批量update,问题就出现在这里!

updateExitStatusByBatch事务进行批量更新的方法假设是B(),其批量更新语句为:

  <update id = "B" parameterType = "java.util.List">

    <foreach collecton = "list" item = "item" separator = ";">

      update t_invest

        set status = 1,

        end_date = #{item.endDate},

        period = #{item.periods},

        update_time = now()

        where invest_no = #{item.invest_no}

    </foreach>

  </update>

(其实两个事务的方法A与B的sql是一样的)

 死锁是因为两个或两个以上的线程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程。

 如下图所示:

t_fixin_invest的事务隔离级别为“可重复读”,每次执行更新操作时会对索引加行锁,在一个事务内批量修改如果没有全部修改完,索引是不会被放开的,亦即索引上的行锁不会被放开,所以当两个事务中同时进行更新时,如果有重复数据,有可能出现互相等待,从而爆死锁。

如上图,syncRedeemApply事务锁住i1、i3、i5,updateExitStatusByBatch事务锁住i2、i4、i6,syncRedeemApply事务执行到i2的update,等待updateExitStatusByBatch事务释放i2的锁,updateExitStatusByBatch事务执行到i1的updat,等待syncRedeemApply事务释放i1的锁,如此,两个事务互相等待,造成死锁。

我的解决办法是避免这两个事务操作使用相同的索引进行更新,给表t_fixin_invest增加一个联合索引(investno,pno),然后其中一个批量操作使用这个索引更新,可避免死锁!

原文地址:https://www.cnblogs.com/pufeng/p/12069835.html

时间: 2024-11-06 22:08:14

一次Mysql下批量更新造成的死锁案例分析的相关文章

(转)一个MySQL 5.7 分区表性能下降的案例分析

一个MySQL 5.7 分区表性能下降的案例分析 原文:http://www.talkwithtrend.com/Article/216803 前言 希望通过本文,使MySQL5.7.18的使用者知晓分区表使用中存在的陷阱,避免在该版本上继续踩坑.同时通过对源码的分享,升级MySQL5.7.18时分区表性能下降的根本原因,向MySQL源码爱好者展示分区表实现中锁的运用. 问题描述 MySQL 5.7版本中,性能相关的改进非常多.包括临时表相关的性能改进,连接建立速度的优化和复制分发相关的性能改进

MySQL批量更新死锁案例分析--转载

问题描述 在做项目的过程中,由于写SQL太过随意,一不小心就抛了一个死锁异常,如下: [java] view plaincopyprint? com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction at sun.reflect.GeneratedConstructorAccessor24

MySQL Workbench批量更新或删除

在使用MySQL Workbench进行批量更新或删除时,会出现如下错误: Error Code: 1175. You are using safe update mode and you tried to update a table without a WHERE that uses a KEY column To disable safe mode, toggle the option in Preferences -> SQL Queries and reconnect. 0.000 s

MySQL死锁案例分析与解决方案

现象: 数据库查询: SQL语句分析: mysql. 并发delete同一行记录,偶发死锁. delete from x_table where id=? 死锁分析: mysql的事务支持与存储引擎有关,MyISAM不支持事务,INNODB支持事务,更新时采用的是行级锁.这里采用的是INNODB做存储引擎,意味着会将update语句做为一个事务来处理.前面提到行级锁必须建立在索引的基础,这条更新语句用到了索引idx_1,所以这里肯定会加上行级锁. 行级锁并不是直接锁记录,而是锁索引,如果一条SQ

2500-使用MyBatis操作MySQL进行批量更新的注意事项

原则上一条SQL只更新一条数据库操作,但有时需要批量操作数据,特别是一些DML语句,在操作数据库时,数据库会报出异常,不允许混合语句,此时需要额外配置进行兼容. 例如: Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server ve

REPEATABLE-READ下批量更新数据的问题

1. 当前mysql的隔离级别 REPEATABLE-READ 2. 用户读取的时候或者更改的时候(通过事务)   会对 更改的数据加行锁 和 gap锁 , 最终更改完毕后 去掉锁. (行锁表示这条数据不能更改, gap锁表示这个索引区域不能被重建) 3. 更改数据无索引的情况, 会锁定全部表,这个很恐怖,不是锁定索引了.(GAP锁是更改数据的时候每遍历一次数据就会加一个gap锁)

Mysql大表查询优化技巧总结及案例分析

http://www.169it.com/article/3219955334.html sql语句使用基本原则:1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引.2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如: select id... sql语句使用基本原则: 1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2

MySql一个生产死锁案例分析

接到上级一个生产环境MySQL死锁日志信息文件,需要找出原因并解决问题.我将死锁日志部分贴出如下: 在mysql中使用命令:SHOW ENGINE INNODB STATUS;总能获取到最近一些问题信息,通过搜索deadlock 关键字即可找到死锁的相关日志信息. 2019-09-25 13:28:25 7fc0301ca700InnoDB: transactions deadlock detected, dumping detailed information. 2019-09-25 13:2

mysql 批量更新与批量更新多条记录的不同值实现方法

在mysql中批量更新我们可能使用update,replace into来操作,下面来给各位详细介绍mysql 批量更新与性能吧! mysql更新语句很简单,更新一条数据的某个字段,一般这样写: 复制代码代码如下: UPDATE mytable SET myfield = 'value' WHERE other_field = 'other_value'; 如果更新同一字段为同一个值,mysql也很简单,修改下where即可: 复制代码代码如下: UPDATE mytable SET myfie