视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
MySQL死锁问题解决的代码详细介绍
2020-11-09 09:09:41 责编:小采
文档


一次MySQL死锁问题解决

一、环境

  • CentOS, MySQL 5.6.21-70, JPA

  • 问题场景:系统有定时批量更新数据状态操作,每次更新上千条记录,表中总记录数约为500W左右。

  • 二、错误日志

    2017-2-25 17:38:41 org.hibernate.util.JDBCExceptionReporter logExceptions
    严重: Lock wait timeout exceeded; try restarting transaction
    2017-2-25 17:39:05 org.hibernate.util.JDBCExceptionReporter logExceptions
    警告: SQL Error: 1213, SQLState: 40001
    2017-2-25 17:39:05 org.hibernate.util.JDBCExceptionReporter logExceptions
    严重: Deadlock found when trying to get lock; try restarting transaction

    三、排查

    Check InnoDB status for locks
    mysql> SHOW ENGINE InnoDB STATUS;
    
    Check MySQL open tables
    mysql> SHOW OPEN TABLES WHERE In_use > 0;
    
    Check pending InnoDB transactions
    mysql> SELECT * FROM `information_schema`.`innodb_trx` ORDER BY `trx_started`; 
    
    Check lock dependency - what blocks what
    mysql> SELECT * FROM `information_schema`.`innodb_locks`;

    排查后发现都是执行类似这样的语句出现问题的:

    update t_task_tel set state='iok', update_date='2017-02-27 11:03:02' where tel_id=66042 and task_id=350199;

    四、分析

    搜索相关资料后发现,原来MySQL InnoDB并不一定都是行级锁。

    相关参考资料片段如下:

    MySQL InnoDB锁机制之Gap Lock、Next-Key Lock、Record Lock解析
    http://www.gxlcms.com/
    
    4、锁选择
    1)、如果更新条件没有走索引,例如执行”update from t1 set v2=0 where v2=5;” ,此时会进行全表扫描,扫表的时候,要阻止其他任何的更新操作,所以上升为表锁。
    2)、如果更新条件为索引字段,但是并非唯一索引(包括主键索引),例如执行“update from t1 set v2=0 where v1=9;” 
    那么此时更新会使用Next-Key Lock。使用Next-Key Lock的原因:
    a)、首先要保证在符合条件的记录上加上排他锁,会锁定当前非唯一索引和对应的主键索引的值;
    b)、还要保证锁定的区间不能插入新的数据。
    3)、如果更新条件为唯一索引,则使用Record Lock(记录锁)。
     
    InnoDB根据唯一索引,找到相应记录,将主键索引值和唯一索引值加上记录锁。但不使用Gap Lock(间隙锁)。
    MySQL InnoDB 锁表与锁行
    http://www.gxlcms.com/
    
    由于InnoDB预设是Row-Level Lock,所以只有「明确」的指定主键,MySQL才会执行Row lock (只锁住被选取的资料例) ,否则MySQL将会执行Table Lock (将整个资料表单给锁住)。

    根据分析结论,猜测是在更新_task_tel表时Where条件中tel_id和task_id没有建立UNIQUE(唯一索引)原因;

    五、解决

    据此分析,尝试通过tel_id和task_id两个字段建立UNIQUE(唯一索引)来解决。 (也可以先查询出来,然后根据主键ID来更新,这样不会因表中数据量较大影响线上业务)。

    通过此种方式解决后,问题没有再重现。

    如果你的问题和我遇到的类似,可以尝试据此解决。

    下载本文
    显示全文
    专题