zoukankan      html  css  js  c++  java
  • innodb next-key lock引发的死锁

    innodb的事务隔离级别是可重复读级别且innodb_locks_unsafe_for_binlog禁用,也就是说允许next-key lock

    CREATE TABLE `LockTest` (
       `order_id` varchar(20) NOT NULL,
       `id` bigint(20) NOT NULL AUTO_INCREMENT,
       PRIMARY KEY (`id`),
       KEY `idx_order_id` (`order_id`)
     ) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8

    事务1 事务2

    begin

    delete from LockTest where order_id =  'D20'

     
      begin

    delete from LockTest where order_id =  'D19'

    insert into LockTest (order_id) values ('D20')

     
     

    insert into LockTest (order_id) values ('D19')

    commit

    commit

    事务1 执行到insert语句会block住,事务2执行insert语句会提示死锁错误

    错误码: 1213
    Deadlock found when trying to get lock; try restarting transaction

    Execution Time : 00:00:00:000
    Transfer Time : 00:00:00:000
    Total Time : 00:00:00:000

     show engine innodb status 显示死锁信息

    ------------------------
    LATEST DETECTED DEADLOCK
    ------------------------
    2014-04-30 15:01:55 a233b90
    *** (1) TRANSACTION:
    TRANSACTION 596042, ACTIVE 7 sec inserting
    mysql tables in use 1, locked 1
    LOCK WAIT 3 lock struct(s), heap size 320, 2 row lock(s), undo log entries 1
    MySQL thread id 10851, OS thread handle 0x2abfb90, query id 251521 10.10.53.122 root update
    insert into LockTest (order_id) values ('D20')
    *** (1) WAITING FOR THIS LOCK TO BE GRANTED:
    RECORD LOCKS space id 502 page no 4 n bits 72 index `idx_order_id` of table `test`.`LockTest` trx id 596042 lock_mode X insert intention waiting
    Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
    0: len 8; hex 73757072656d756d; asc supremum;;

    *** (2) TRANSACTION:
    TRANSACTION 596041, ACTIVE 19 sec inserting
    mysql tables in use 1, locked 1
    3 lock struct(s), heap size 320, 2 row lock(s), undo log entries 1
    MySQL thread id 10848, OS thread handle 0xa233b90, query id 251522 10.10.53.122 root update
    insert into LockTest (order_id) values ('D19')
    *** (2) HOLDS THE LOCK(S):
    RECORD LOCKS space id 502 page no 4 n bits 72 index `idx_order_id` of table `test`.`LockTest` trx id 596041 lock_mode X
    Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
    0: len 8; hex 73757072656d756d; asc supremum;;

    *** (2) WAITING FOR THIS LOCK TO BE GRANTED:
    RECORD LOCKS space id 502 page no 4 n bits 72 index `idx_order_id` of table `test`.`LockTest` trx id 596041 lock_mode X insert intention waiting
    Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
    0: len 8; hex 73757072656d756d; asc supremum;;

    *** WE ROLL BACK TRANSACTION (2)

    简单分析上面的场景先删除再插入的sql是hibernage保存集合关联的处理方式。delete语句删除不存在且删除的order_id大于现有表中的所有order_id,所以delete语句会使用next-key锁住(当前最大-无穷大) 

    lock_id lock_trx_id lock_mode lock_type lock_table lock_index lock_space lock_page lock_rec lock_data
    596133:502:4:1 596133 X RECORD `test`.`LockTest` idx_order_id 502 4 1 supremum pseudo-record
    596134:502:4:1 596134 X RECORD `test`.`LockTest` idx_order_id 502 4 1 supremum pseudo-record

    比较奇怪的是为啥两个事务都拿到了相同区间的(当前最大-无穷大)的X锁。不过换成read-commited级别后就没死锁了。

    终于在官方文档找到答案, 区间锁只是用来防止其他事务在区间中插入数据,区间x锁 与区间S锁效果是一样的。也就是说不会因为两个事务都用加相同区间锁而相互等待的

    https://dev.mysql.com/doc/refman/5.1/en/innodb-record-level-locks.html

    Gap locks in InnoDB are purely inhibitive, which means they only stop other transactions from inserting to the gap. Thus, a gap X-lock has the same effect as a gap S-lock.

    当两个事务拿到相同区间锁后,就会阻止对方忘区间内做insert操作。所以第一个事务insert会阻塞,第二个事务会提示死锁

  • 相关阅读:
    java web项目防止多用户重复登录解决方案
    java提高篇(二一)-----ArrayList
    转:为什么需要htons(), ntohl(), ntohs(),htons() 函数
    转:对于linux下system()函数的深度理解(整理)
    转:sprintf与snprintf
    转: fscanf()函数详解
    转:fopen()函数
    转:struct sockaddr与struct sockaddr_in ,struct sockaddr_un的区别和联系
    转:BZERO()等的区别
    转:Linux内存管理之mmap详解
  • 原文地址:https://www.cnblogs.com/xhan/p/3701459.html
Copyright © 2011-2022 走看看