MySql InnoDB可重复读取锁的意外行为

时间:2017-03-31 13:47:04

标签: mysql transactions innodb snapshot database-deadlocks

据我所知,innoDB使用一致的非阻塞读取机制, 所以每个事务都使用自己的快照。

它也在官方documentation

中被告知
  

一致读取不会对其访问的表设置任何锁定,因此其他会话可以在对表执行一致读取的同时自由修改这些表。

但是当我经典地阅读/更新'出现死锁:

  1. 隔离级别 可重复读取(也可通过 READ COMMITTED 再现)

  2. 交易1 读取行( 锁定共享模式)。

  3. 事务2 读取同一行( 锁定共享模式)。 然后

  4. 事务1 尝试更新此行。

  5. 交易2 也会尝试更新此行。

  6. 在最后一步之后,innoDB检测到死锁(下面有最新检测到的DEADLOCK):     ----------------     2017-03-31 16:07:03 0x1f58     ***(1)交易:     TRANSACTION 413412,ACTIVE 20秒开始索引读取     mysql表在使用1,锁定1     LOCK WAIT 9个锁结构,堆大小1136,6个行锁,撤消日志条目3     MySQL线程ID 33,OS线程句柄8148,查询ID 102005 localhost 127.0.0.1 root更新

    /* update Order */ update `Order` set ... <fields to update>
    
    *** (1) WAITING FOR THIS LOCK TO BE GRANTED:
    RECORD LOCKS space id 2151 page no 709 n bits 88 index PRIMARY of table `ooapp2`.`order` trx id 413412 lock_mode X locks rec but not gap waiting
    Record lock, heap no 3 PHYSICAL RECORD: n_fields 54; compact format; info bits 0
    
    *** (2) TRANSACTION:
    TRANSACTION 413413, ACTIVE 11 sec starting index read
    mysql tables in use 1, locked 1
    9 lock struct(s), heap size 1136, 6 row lock(s), undo log entries 3
    MySQL thread id 28, OS thread handle 8024, query id 102008 localhost 127.0.0.1 root updating
    
    /* update Order */ update `Order` set ...<fields to update>
    
    *** (2) **HOLDS THE LOCK(S):**
    RECORD LOCKS space id 2151 page no 709 n bits 88 index PRIMARY of table `ooapp2`.`order` trx id 413413 lock mode S locks rec but not gap
    Record lock, heap no 3 PHYSICAL RECORD: n_fields 54; compact format; info bits 0
    
    *** (2) WAITING FOR THIS LOCK TO BE GRANTED:
    RECORD LOCKS space id 2151 page no 709 n bits 88 index PRIMARY of table `ooapp2`.`order` trx id 413413 lock_mode X locks rec but not gap waiting
    Record lock, heap no 3 PHYSICAL RECORD: n_fields 54; compact format; info bits 0
    
     *** WE ROLL BACK TRANSACTION (2)
    

    我无法理解,会发生什么,为什么要进行交易2

      

    LOL THE LOCK(S)

    所以如果innoDB不使用Consistent Read with snapshot并设置S-locks 这与官方手册中的事实不符。

1 个答案:

答案 0 :(得分:1)

不要那样做。如果您可能正在更新某行,但同时需要该值,请使用SELECT ... FOR UPDATE;。就这样做,忘了tx_isolation。通常,这会将死锁变为延迟。 (参见innodb_lock_wait_timeout,默认为超过50秒。)

此外,当您执行获取死锁时,请重新运行整个事务。无论你多么努力地避免死锁,都会发生僵局。