`

mysql 检测死锁

阅读更多

一个MySQL死锁问题的解决最近在项目开发过程中,碰到了数据库的死锁问题,在解决问题的过程中,加深了对MySQL InnoDB引擎锁机制的理解。

我们使用Show innodb status检查引擎状态时,发现了死锁问题:

*** (1) TRANSACTION:
TRANSACTION 0 677833455, ACTIVE 0 sec, process no 11393, OS thread id 278546 starting index read
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 320
MySQL thread id 83, query id 162348740 dcnet03 dcnet Searching rows for update
update TSK_TASK set STATUS_ID=1064,UPDATE_TIME=now () where STATUS_ID=1061 and MON_TIME<date_sub(now(), INTERVAL 30 minute)
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 849384 n bits 208 index `PRIMARY` of table `dcnet_db/TSK_TASK` trx id 0 677833455 lock_mode X locks rec but not gap waiting
Record lock, heap no 92 PHYSICAL RECORD: n_fields 11; compact format; info bits 0
0: len 8; hex 800000000097629c; asc      b ;; 1: len 6; hex 00002866eaee; asc  (f  ;; 2: len 7; hex 00000d40040110; asc    @  ;; 3: len 8; hex 80000000000050b2; asc      P ;; 4: len 8; hex 800000000000502a; asc      P*;; 5: len 8; hex 8000000000005426; asc      T&;; 6: len 8; hex 800012412c66d29c; asc    A,f  ;; 7: len 23; hex 75706c6f6164666972652e636f6d2f6 8616e642e706870; asc xxx.com/;; 8: len 8; hex 800000000000042b; asc        +;; 9: len 4; hex 474bfa2b; asc GK +;; 10: len 8; hex 8000000000004e24; asc      N$;;

*** (2) TRANSACTION:
TRANSACTION 0 677833454, ACTIVE 0 sec, process no 11397, OS thread id 344086 updating or deleting, thread declared inside InnoDB 499
mysql tables in use 1, locked 1
3 lock struct(s), heap size 320, undo log entries 1
MySQL thread id 84, query id 162348739 dcnet03 dcnet Updating
update TSK_TASK set STATUS_ID=1067,UPDATE_TIME=now () where ID in (9921180)
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 0 page no 849384 n bits 208 index `PRIMARY` of table `dcnet_db/TSK_TASK` trx id 0 677833454 lock_mode X locks rec but not gap
Record lock, heap no 92 PHYSICAL RECORD: n_fields 11; compact format; info bits 0
0: len 8; hex 800000000097629c; asc      b ;; 1: len 6; hex 00002866eaee; asc  (f  ;; 2: len 7; hex 00000d40040110; asc    @  ;; 3: len 8; hex 80000000000050b2; asc      P ;; 4: len 8; hex 800000000000502a; asc      P*;; 5: len 8; hex 8000000000005426; asc      T&;; 6: len 8; hex 800012412c66d29c; asc    A,f  ;; 7: len 23; hex 75706c6f6164666972652e636f6d2f6 8616e642e706870; asc uploadfire.com/hand.php;; 8: len 8; hex 800000000000042b; asc        +;; 9: len 4; hex 474bfa2b; asc GK +;; 10: len 8; hex 8000000000004e24; asc      N$;;

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 843102 n bits 600 index `KEY_TSKTASK_MONTIME2` of table `dcnet_db/TSK_TASK` trx id 0 677833454 lock_mode X locks rec but not gap waiting
Record lock, heap no 395 PHYSICAL RECORD: n_fields 3; compact format; info bits 0
0: len 8; hex 8000000000000425; asc        %;; 1: len 8; hex 800012412c66d29c; asc    A,f  ;; 2: len 8; hex 800000000097629c; asc      b ;;

*** WE ROLL BACK TRANSACTION (1)

该死锁问题涉及TSK_TASK表,该表用于保存系统监测任务,相关字段及索引如 下:


ID:主键;

MON_TIME:监测时间;

STATUS_ID:任务状态;

索 引:KEY_TSKTASK_MONTIME2 (STATUS_ID, MON_TIME)。


经分析,涉及的两条语句应该不会 涉及相同的TSK_TASK记录,那为什么会造成死锁呢?

查询MySQL官网文档,发现这跟MySQL的索引机制有关。MySQL的 InnoDB引擎是行级锁,我原来的理解是直接对记录进行锁定,实际上不是这样的,其要点如下:


不是对记录进行锁定,而是对索引 进行锁定;

在UPDATE、DELETE操作时,MySQL不仅锁定WHERE条件扫描过的所有索引记录,而且会锁定相邻的键值,即所谓 的next-key locking;
如语句UPDATE TSK_TASK SET UPDATE_TIME = NOW() WHERE ID > 10000会锁定所有主键大于等于1000的所有记录,在该语句完成之前,你就不能对主键等于10000的记录进行操作;

当 非簇索引(non-cluster index)记录被锁定时,相关的簇索引(cluster index)记录也需要被锁定才能完成相应的操作。

再 分析一下发生问题的两条SQL语句,就不难找到问题所在了:

当“update TSK_TASK set STATUS_ID=1064,UPDATE_TIME=now () where STATUS_ID=1061 and MON_TIME<date_sub(now(), INTERVAL 30 minute)”执行时,MySQL会使用KEY_TSKTASK_MONTIME2索引,因此首先锁定相关的索引记录,因为 KEY_TSKTASK_MONTIME2是非簇索引,为执行该语句,MySQL还会锁定簇索引(主键索引)。

假设“update TSK_TASK set STATUS_ID=1067,UPDATE_TIME=now () where ID in (9921180)”几乎同时执行时,本语句首先锁定簇索引(主键),由于需要更新STATUS_ID的值,所以还需要锁定 KEY_TSKTASK_MONTIME2的某些索引记录。

这样第一条语句锁定了KEY_TSKTASK_MONTIME2的记录,等待 主键索引,而第二条语句则锁定了主键索引记录,而等待KEY_TSKTASK_MONTIME2的记录,这样死锁就产生了。

我们通过拆分 第一条语句解决了死锁问题:即先查出符合条件的ID:select ID from TSK_TASK where STATUS_ID=1061 and MON_TIME < date_sub(now(), INTERVAL 30 minute);然后再更新状态:update TSK_TASK set STATUS_ID=1064 where ID in (….)

这样就不会产生索引的竞争问题,死锁问题就 解决了。

分享到:
评论

相关推荐

    mysql死锁检测机制初探1

    mysql死锁检测机制初探1

    mysql innodb死锁问题详解.docx

    数据库也会发生死锁的现象,数据库系统实现了各种死锁检测和死锁超时机制来解除死锁,锁监视器进行死锁检测,MySQL的InnoDB处理死锁的方式是 将持有最少行级排它锁的事务进行回滚,相对比较简单的死锁回滚办法

    mysql服务检测并自动重启

    基于windows server 平台,检测mysql服务,如果发现数据库被死锁进行系统调用,重启mysql服务,使用Java和idea intellij开发,整个工程包含了pom清单

    详解MySQL(InnoDB)是如何处理死锁的

    主要介绍了MySQL(InnoDB)是如何处理死锁的,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

    MySQL Innodb表导致死锁日志情况分析与归纳

    案例描述在定时脚本运行过程中,发现当备份表格的sql语句与删除该表部分数据的sql语句同时运行时,mysql会检测出死锁,并打印出日志。两个sql语句如下:(1)insert into backup_table select * from source_table...

    详解SQL死锁检测的方法

    sql server中的死锁是指进程之间互相永久阻塞的状态,下文就将为您介绍如何检测sql server死锁,希望对您有所帮助。 死锁(deadlock)指进程之间互相永久阻塞的状态,SQL可以检测到死锁,并选择终止其中一个事务以...

    10道精选MySQL面试题

    10道精选MySQL面试题: 请简述B树和B+树在MySQL数据库索引中...MySQL如何检测和处理死锁? 分区表是如何工作的?在哪些场景下使用分区表能提升查询或写入性能? 如果业务需要进行水平拆分,你将如何设计分库分表策略?

    transaction_retry:重试有关死锁和事务序列化错误的数据库事务。 支持MySQL,PostgreSQL和SQLite

    transaction_retry 重试有关死锁和事务序列化错误的数据库事务。 支持MySQL,PostgreSQL和SQLite。 例子 通过拯救ActiveRecord :: TransactionIsolationConflict并重试事务,gem自动工作。...检测到死锁

    mysql数据库my.cnf配置文件

    InnoDB在它自己的锁定表中自动检测事务死锁并且回滚事务。InnoDB用LOCK TABLES语句注意到锁定设置。默认值是50秒 bulk_insert_buffer_size = 1024M # 批量插入缓存大小, 这个参数是针对MyISAM存储引擎来说的。适用...

    sql测试语句

    mysql数据库sql语句测试,包含crud,日期函数,字符函数,聚合函数等 ,还有隐式转换和死锁检测。

    MYSQL METADATA LOCK(MDL LOCK)MDL锁问题分析

    简单的所谓的Waiting for table metadata lock之类的状态,其实MDL LOCK是MYSQL上层一个非常复杂的子系统,有自己的死锁检测机制 (无向图?)而大家一般口中的是不是锁表了其实就是指的它,可见的它的关键性和严重性...

    MySQL的事务与锁解析

    本文8500多字,5个大目录一、什么是事务1.... 死锁的发生和检测3. 查看锁的信息4. 死锁的避免 一、什么是事务 1. 使用场景 项目里面,比如有涉及到转账、操作订单之类的,我们需要让这些操作在一个事务里面

    服务器监控王

    ServerKing 服务器监控王能够实时监控 WWW 服务、 IIS 程序池、网卡流量、异常进程、 CPU 资源占用率、内存使用率、硬盘空间、 MSSQL 内存清空、 MySQL 服务等近 10 多项功能,当检测值达到用户设定的报警阀值时...

    Cm_RedisSession:具有乐观锁定的Magento的基于Redis的会话处理程序

    Cm_RedisSession Magento的基于Redis的会话处理程序,具有乐观锁定。 特征: ... 检测崩溃的进程以防止会话死锁(仅Linux)。 使机器人和搜寻器的会话寿命更短,以减少浪费的资源。 可以使用config或de

    题库系统源码.zip

    ·[新功能] ProviderTrait新增是否排序自动检测 ·[新功能] 数据库兼容MySQL8.0 ·[新功能] OpenApi和Api中间件新增AccessGate ·[新功能] 文件上传表新增大类和分类索引 ·[新功能] Request新增isGet方法用于...

    魔众题库系统 v7.6.0.zip

    ·[新功能] ProviderTrait新增是否排序自动检测 ·[新功能] 数据库兼容MySQL8.0 ·[新功能] OpenApi和Api中间件新增AccessGate ·[新功能] 文件上传表新增大类和分类索引 ·[新功能] Request新增isGet方法用于...

    常用数据库管理系统简介.docx

    自动检测死锁冲突并解决。 数据安全级别为C2级(最高级)。 ,数据库内模支持多字节码制,支持多种语言文字编码。 ,具有面向制造系统的管理信息系统和财务应用系统。 常用数据库管理系统简介全文共5页,当前为第1页...

    Discuz 2.5 最新版

    采用全新的帖子查看数更新机制,解决大访问量情况下,因瞬间大批量更新主题表造成的MySQL死锁的问题; 用户表支持内存级缓存启用;同时,新增不活跃用户(大部分站点比例超过70%)归档功能,让用户表只保留最近活跃用户...

    sqlcore数据库防注入分析系统

    sqlcore是一套方便的基于java应用系统数据的的检查工具,方便简单,是现代系统的自动化检测的有效工具 sqlcore可以用于如下的使用场景: 1.数据库的注入分析 2.数据库sql的执行效率分析 3.平台的监控和业务逻辑的...

Global site tag (gtag.js) - Google Analytics