mysql for update lock 悲观锁 解决并发问题

mysql常用的锁有for update 和 for update in share mode两种

锁的区别

  • for update 我认为是悲观锁,其他事务读会被阻塞等待,写被禁止,且不准多次加锁
  • for update in share mode 读取不等待,写入会被禁止,可被多次加锁

in share mode的问题
如果两个事务对同一行数据加锁很容易导致,两个事务都更新失败

使用场景

基于以上特点介绍,in share mode可以用于两个表关联时,保护主表数据不被修改,for update更适合保护单表单行数据的正确性,适合投票、提现等场景

测试验证

以下代码验证for update的作用
表maxcount中marks初始为8,每次减1,当他大于0时,将当时数据保存,类似于抽奖中控制最大奖品数的问题
tp中lock(true)会默认使用for update锁,我们每次测试修改代码即可

并发配置

使用ab发400并发

ab -n 400 -c 400 http://127.0.0.1/

测试代码

$marks = -1;
Db::transaction(function() use ($maxcount,&$marks,$meta){
    $max = $maxcount->where([
        'userid' => 'shuaka1500',
        'reason' => '2018-09-06 00:00:00',
    ])->lock(true)->find();
    $max->setDec('marks', 1);
    $marks = $max->marks;

    if ($marks >= 0)
    {
        $meta->data([
            'post_id'=>$marks
        ], true);
        $meta->save();
    }
});

事务+for update

这是正确的用法,我们发现数据记录都是合理的,并且数据都是按顺序记录,有效解决了并发问题
正确1.1.JPG

无事务+无锁

这时数据出现了错误,但是由于没有开启事务,性能比较强,所以并没有多记录
错误1.JPG

事务+无锁

由于开启了事务,mysql性能下降,又没有正确使用锁,在并发时多记录了数据,如果这时抽奖,发出的奖品就会过多问题严重,本来8个奖品,现在发了10个出去
错误2.JPG

相关文章

已有 2 条评论
  1. 安伟

    恭喜老范喜提678篇技术好文。

    安伟
  2. 云璃

    恭喜老范喜提678篇技术好文。

    云璃

此处评论已关闭