mysql delete in死锁_Innodb锁系统 Insert/Delete 锁处理及死锁示例分析

A.INSERT

插入操作在函数btr_cur_optimistic_insert->btr_cur_ins_lock_and_undo->lock_rec_insert_check_and_lock这里进行锁的判断,我们简单的看看这个函数的流程:

1.首先先看看欲插入记录之后的数据上有没有锁,

next_rec = page_rec_get_next_const(rec);

next_rec_heap_no = page_rec_get_heap_no(next_rec);

lock = lock_rec_get_first(block, next_rec_heap_no);

如果lock为空的话,对于非聚集索引,还需要更新page上的最大事务ID。

实际上这里是比较松散的检查,大并发插入的时候,可以大大的降低创建锁开销。

那么其他事务如何发现这些新插入的记录呢(重复插入同一条记录显然应该被阻塞),这里会有个判断,其他事务去看看

新插入记录的事务是否还是活跃的,如果还是活跃的,那么就为这个事务主动增加一个锁记录(所谓的隐式锁就是么有锁。。。。),这个判断是在检查是否存在冲突键的时候进行的(row_ins_duplicate_error_in_clust->row_ins_set_shared_rec_lock->lock_clust_rec_read_check_and_lock->lock_rec_convert_impl_to_expl

row_ins_set_shared_rec_lock的目的是为了向记录上加一个LOCK_REC_NOT_GAP的LOCK_S锁,也就是非GAP的记录S锁,如果发现记录上有X锁(隐式锁转换为LOCK_REC | LOCK_X | LOCK_REC_NOT_GAP),显然是需要等待的(返回DB_LOCK_WAIT)

这里设置inherit为FALSE,然后返回DB_SUCCESS;

至于inherit的作用,稍后再议!

2.如果lock不为空,这意味着插入记录的下一个记录上存在锁,设置inherit为TRUE.

检查下一个记录上的锁是否和LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION相互冲突

if (lock_rec_other_has_conflicting(

LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION,

block, next_rec_heap_no, trx)) {

/* Note that we may get DB_SUCCESS also here! */

err = lock_rec_enqueue_waiting(LOCK_X | LOCK_GAP

| LOCK_INSERT_INTENTION,

block, next_rec_heap_no,

index, the);

如果有别的事务在下一个记录上存在显式的锁请求,并且和锁模式( LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION) 冲突,那么

这时候当前事务就需要等待。

如果别的事务持有一个GAP类型的锁以等待插入,我们认为这个锁和当前插入不冲突。

如何判定锁之间是否冲突,在上一篇博客(http://mysqllover.com/?p=425)已经介绍过,不再赘述.

当检查到存在冲突的事务,我们就将一个锁模式为LOCK_X | LOCK_GAP|LOCK_X | LOCK_GAP 加入到请求队列中(调用函数lock_rec_enqueue_waiting),这里也会负责去检查死锁。

注意在加入等待队列的时候可能会返回DB_SUCCESS,例如死锁发生,但选择另外一个事务为牺牲者。

我们上面提到变量inherit,在存在下一个记录锁时会设置为TRUE,在上层函数btr_cur_optimistic_insert,会据此进行判断:

if (!(flags & BTR_NO_LOCKING_FLAG) && inherit) {

lock_update_insert(block, *rec);

}

注意当我们执行到这部分逻辑时err为DB_SUCCESS,表示锁检查已经通过了。

BTR_NO_LOCKING_FLAG表示不做记录锁检查

对于optimistic_insert, flags值为0

对于pessimistic_insert,flags值为BTR_NO_UNDO_LOG_FLAG | BTR_NO_LOCKING_FLAG | BTR_KEEP_SYS_FLAG

因此对于乐观更新(无需修改BTREE结构),当inherit被设置为TRUE时,总会调用lock_update_insert

根据注释,lock_update_insert用于继承下一条记录的GAP锁,流程如下

1.首先获取插入的记录的heap no和下一条记录的heap no

receiver_heap_no = rec_get_heap_no_new(rec);

<
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值