MDL LOCK 死锁一例

来源:这里教程网 时间:2026-03-01 18:31:38 作者:

例子1:

trx1 trx2
begin;select * from test
alter table test add col1 int;(堵塞)
delete from test limit 1;(死锁)

例子2:

trx1 trx2
begin;delete from test limit 1;或者for update语句
alter table test add col1 int;(堵塞)
delete from test limit 1;(通过)

MDL LOCK在获取的时候首先会检测是否本事务中曾经获取过同样类型或者更强的MDL LOCK,这个类型包含锁的对象,锁的等级,持续周期等,如果检测通过则不需要进入优先级和兼容矩阵判断,也就是不会判断是否堵塞,而是直接获得一把锁,因此大概的流程为,这个流程不适用于同一个事务,必须要有2个以上交叉的事务:

    1. 判断本事务获取过同样的MDL LOCK(或者强度更高),如果有就直接获取,不需要下面步骤,强度排行大约为
    S SH SR SW SWLP SU SRO SNW SNRW X----------------------------------->弱                              强
    1. 如果没有,则判断优先级矩阵,用于判断是否当前获取的MDL LOCK优先级更高,不会被堵塞中的MDL LOCK堵塞,如果是则走下一步,如果不是则直接堵塞
    1. 如果优先级矩阵判断通过,也就是不会被堵塞中的MDL LOCK堵塞,则获取的MDL LOCK和本次获取的兼容矩阵进行判断,如果判断兼容则通过,不堵塞。

    例子1

    trx1 select 语句获取单存的select语句获取的是SR MDL LOCK锁,而trx2的 alter table 语句会在第一阶段上X锁,很明显不兼容因此堵塞,

           Request  |  Granted requests for lock            |
            type    | S  SH  SR(这里) SW  SWLP  SU  SRO  SNW  SNRW  X  |
          ----------+---------------------------------------------+
          X         | -   -   -       -    -    -   -    -    -    -  |

    因此alter 语句堵塞,然后trx1的 delete from 语句需要获取的是SW MDL LOCK,因为这个时候trx2的X锁处于等待,因此在判断优先级矩阵的时候如下,

           Request  |         Pending requests for lock          |
            type    | S  SH  SR  SW  SWLP  SU  SRO  SNW  SNRW  X(这里) |
          ----------+--------------------------------------------+
          SW        | +   +   +   +    +    +   +    -     -   - |

    这部分代码如下,

    2547      if (!(m_waiting.bitmap() & waiting_incompat_map))
    //这里比较就是优先级矩阵,直接返回了false
    (gdb) n
    2601      return can_grant;
    (gdb) p can_grant
    $4 = false

    因此trx1 堵塞,这样环形等待出现,MDL LOCK报出了死锁。

    例子2

    这部分trx2和上面一样,但是问题在于trx1 一开头就获取了一个SW锁,这里DML/for update 语句都是SW MDL LOCK,且对象为test表,持续周期为事务。而第二个delete语句也会需要同样的MDL LOCK,因此在校验的第1步就通过直接获取了不需要在判断是否堵塞的问题了。因此这个例子没有产生死锁。

    而这种死锁为MDL LOCK死锁不在innodb层而是在mysql层,因此show engine 是看不到的。

    trx1 trx2
    begin;delete from test limit 1;或者for update语句
    alter table test add col1 int;(堵塞)
    select * from test;(通过)

    其他

    //强度排行判定bool MDL_ticket::has_stronger_or_equal_type(enum_mdl_type type) const{
      const MDL_lock::bitmap_t *
        granted_incompat_map= m_lock->incompatible_granted_types_bitmap();
      return ! (granted_incompat_map[type] & ~(granted_incompat_map[m_type]));}   //              sw                                  sr                                                
        //        ! 1111000000 &  ~110000000
        //         ! 11000000  为 flase  SR等级比SW低  相反SW比SR高//兼容级矩阵判定bool MDL_ticket::is_incompatible_when_granted(enum_mdl_type type) const{
      return (MDL_BIT(m_type) &
              m_lock->incompatible_granted_types_bitmap()[type]);}
     MDL_EXCLUSIVE//优先级矩阵判定boolMDL_ticket::is_incompatible_when_waiting(enum_mdl_type type) const{
      return (MDL_BIT(m_type) &
              m_lock->incompatible_waiting_types_bitmap()[type]);}

  • 相关推荐