mysql更新死锁问题

mysql更新死锁问题

问题现象

同一时间点,一个商户下多个模板(模板id不同)同时更新;
券模板操作流水更新时发生死锁,报 Deadlock found when trying to get lock; try restarting transaction 错误

相关业务表信息

  • 表:log_xx
  • 索引信息:log_no:分库分表全局唯一uk; merchant_id: 普通索引

业务处理逻辑

  • 1、启动本地事务
  • 2、按照logNo + merchantPid加锁查询流水表;
    • 伪代码SQL:select * from log_xx where log_no='#logNo#' and merchant_id='#merchantPid#'
  • 3、业务处理(含流水表及本地其他表插入、更新等。。。)
  • 4、业务处理完毕,按照logNo + merchantPid更新流水表;
    • 伪代码SQL:update log_xx set 字段X=value_Y where log_no='#logNo#' and merchant_id='#merchantPid#'
  • 5、事务提交

问题原因

mysql使用了index merge,update语句中where条件走多索引且并发高时有概率出现死锁

  • update时,如果where条件里面涉及多个字段,区分度都比较高且字段都分别建了索引的话,mysql会多个索引各走一遍,然后结果取个交集;
  • 单条记录更新不会引发问题; 多条记录并发更新时,如果索引行数有重叠,因加锁顺序可能不同,互相等待可能会导致死锁,为什么加锁顺序会不同呢?我们的sql中where条件的顺序是一定的,那么加锁顺序也应该一定,为什么会有加锁顺序不同情况。情况是这样的,因为我们使用的是两个单值索引,where条件中是复合条件,那么mysql会使用index merge进行优化,优化过程是mysql会先用索引1进行扫表,在用索引2进行扫表,然后求交集形成一个合并索引。这个使用索引扫表的过程和我们本身的sql使用索引的顺序可能存在互斥,所以造成了死锁。
  • 更多问题说明及解决方案请参见https://bugs.mysql.com/bug.php?id=77209

解决方案

  • 方案一:流水表中log_no是全局唯一的,更新表时只使用log_no作为查询条件; 如果期望校验merchantId的合法性,查出单条记录后放业务中作;
  • 方案二:根据以上文档说明,使用update force index理论上也能解决问题; 针对自身业务,相比而言上个方案更优,暂不采用该方案;

问题相关记录及截图

  • 待更新的两条log,商户id都是2088702993114853,但log_no不同;
  • 第一个线程 traceId=0ad5798414695108358467441_0_b8043a84_7_1_4_20
    • 2016-07-26 13:27:16,871
      select * from log_85 where log_no='894185' and merchant_id=' 114853'
    • 2016-07-26 13:27:17,269
      update log_85 set 字段xx=value xx where log_no='894185' and merchant_id='114853'
  • 第二个线程 traceId=0ad5798414695108358467441_0_b8043a84_7_1_12_20
    • 2016-07-26 13:27:16,868
      select * from log_85 where log_no=893985' and merchant_id='114853'
    • 2016-07-26 13:27:17,179
      update 85 set 字段xx=value xx where log_no='893985' and merchant_id='114853'
  • 更新log表使用了intersect

  • 错误日志堆栈
    --- Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction; nested exception is com.ibatis.common.jdbc.exception.NestedSQLException:

上一篇: 无

你可能感兴趣的:(mysql更新死锁问题)