• ADADADADAD

    innodb next-key lock引发的死锁现象分析[ mysql数据库 ]

    mysql数据库 时间:2024-12-24 19:10:20

    作者:文/会员上传

    简介:

    这个例子是我在网上看到的,我分析了很久才弄明白锁产生的具体过程。

    数据库的事务隔离级别是RR。

    建测试表:
    CREATETABLE`LockTest`(`order_id`varchar(20)NOTNULL,`id`bigi

    以下为本文的正文内容,内容仅供参考!本站为公益性网站,复制本文以及下载DOC文档全部免费。

    这个例子是我在网上看到的,我分析了很久才弄明白锁产生的具体过程。

    数据库的事务隔离级别是RR。

    建测试表:
    CREATETABLE`LockTest`(
    `order_id`varchar(20)NOTNULL,
    `id`bigint(20)NOTNULLAUTO_INCREMENT,
    PRIMARYKEY(`id`),
    KEY`idx_order_id`(`order_id`)
    )ENGINE=InnoDBAUTO_INCREMENT=16DEFAULTCHARSET=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语句会提示死锁错误。

    原因分析:
    1、首先看测试表的建表语句,id是主键索引,同时该主键是自增主键。order_id是普通索引。
    2、事务1执行delete from LockTest where order_id = 'D20';语句时,由于数据库的隔离级别是RR,因此此时事务1在主键id上获得了一个next-key lock,这个锁的范围是[16, +∞)。
    这个16就来自于AUTO_INCREMENT=16,因为LockTest目前是张空表。
    3、同理,事务2执行delete from LockTest where order_id = 'D19';语句时,由于数据库的隔离级别是RR,事务2在主键id上也获得了一个next-key lock,这个锁的范围是[16, +∞)。
    也就是说此时,事务1和事务2获得的锁是一样的。
    4、事务1继续执行insert into LockTest (order_id) values ('D20');语句,这个时候由于该语句企图往LockTest表insert一行id=16,order_id=D20的数据,
    但是由于在事务2的delete语句中,主键id上已经有了一个范围为[16, +∞)的锁,导致事务1此时想插入数据插不进去,被阻塞了。
    5、继续事务2的插入语句insert into LockTest (order_id) values ('D19'); 该插入语句同样也想往LockTest表insert一行id=16,order_id=D19的数据,
    但是由于由于在事务1的delete语句中,主键id上已经有了一个范围为[16, +∞)的锁,导致事务2此时想插入数据插不进去,被阻塞了。
    此时,可以发现,事务1和事务2的锁是互相持有,互相等待的。所以innodb判断该事务遇到了死锁,直接将事务2进行了回滚。然后回头去看事务1,insert into LockTest (order_id) values ('D20');被成功执行。

    如果你将数据库的事务隔离级别修改为RC,上述事务会各自成功运行,不会互相影响。





    innodb next-key lock引发的死锁现象分析.docx

    将本文的Word文档下载到电脑

    推荐度:

    下载
    热门标签: innodblocknextkey