巧用MySQL InnoDB引擎锁机制解决死锁问题

  • 来源: 赛迪网 作者: 若水   2008-04-24/15:22
  • MYSQL客户端下载:Navicat for MySQL简体中文版V8.1.20

    最近,在项目开发过程中,碰到了数据库死锁问题,在解决问题的过程中,笔者对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*** (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)。

    在一个update和insert操作频繁的表中,少量数据测试的时候运行良好,在实际运营中,因数据量比较大(21万条记录),会出现死锁现象,用show processlist查看#p#分页标题#e#,可以看到一个update语句状态是Locked,一个delete语句状态是Sending data。查看了一下参考手册,把锁定相关的资料整理下来,以便自己记录和追踪该问题的解决情况:

    MySQL 5.1支持对MyISAM和MEMORY表进行表级锁定,对BDB表进行页级锁定,对InnoDB 表进行行级锁定。在许多情况下,可以根据培训猜测应用程序使用哪类锁定类型最好,但一般很难说出某个给出的锁类型就比另一个好。一切取决于应用程序,应用程序的不同部分可能需要不同的锁类型。为了确定是否想要使用行级锁定的存储引擎,应看看应用程序做什么并且混合使用什么样的选择和更新语句。例如,大多数Web应用程序执行许多选择,而很少进行删除,只对关键字的值进行更新,并且只插入少量具体的表。基本MySQL MyISAM设置已经调节得很好。

    在MySQL中对于使用表级锁定的存储引擎,表锁定时不会死锁的。这通过总是在一个查询开始时立即请求所有必要的锁定并且总是以同样的顺序锁定表来管理

    对WRITE,MySQL使用的表锁定方法原理如下:

    ◆ 如果在表上没有锁,在它上面放一个写锁。

    ◆否则,把锁定请求放在写锁定队列中。

    对READ,MySQL使用的锁定方法原理如下:

    ◆如果在表上没有写锁定,把一个读锁定放在它上面。

    ◆否则,把锁请求放在读锁定队列中。

    当一个锁定被释放时,锁定可被写锁定队列中的线程得到,然后是读锁定队列中的线程。

    这意味着,如果你在一个表上有许多更新,SELECT语句将等待直到没有更多的更新。

    如果INSERT 语句不冲突,可以自由为MyISAM 表混合并行的INSERT 和SELECT 语句而不需要锁定。

    InnoDB 使用行锁定,BDB 使用页锁定。对于这两种存储引擎,都可能存在死锁。这是因为,在SQL语句处理期间,InnoDB 自动获得行锁定,BDB 获得页锁定,而不是在事务启动时获得。

    行级锁定的优点:

    · 当在许多线程中访问不同的行时只存在少量锁定冲突。

    · 回滚时只有少量的更改。

    · 可以长时间锁定单一的行。

    行级锁定的缺点:

    · 比页级或表级锁定占用更多的内存。

    · 当在表的大部分中使用时,比页级或表级锁定速度慢,因为你必须获取更多的锁。

    · 如果你在大部分数据上经常进行 GROUP BY 操作或者必须经常扫描整个表,比其它锁定明显慢很多。

    · 用高级别锁定,通过支持不同的类型锁定,你也可以很容易地调节应用程序,因为其锁成本小于行级锁定。


    评论 {{userinfo.comments}}

    {{money}}

    {{question.question}}

    A {{question.A}}
    B {{question.B}}
    C {{question.C}}
    D {{question.D}}
    提交

    驱动号 更多