新闻中心

记录团队成长点滴以及对技术、理念的探索,同时我们乐于分享!

php常见处理并发解决方案

2020-10-18 10:29:08 分类:技术学堂

常见的并发处理如下:


1.悲观锁


为什么叫悲观锁?


默认每次的执行都会发生并发


表必须是innodb类型,必须在事务中执行,加上for update 查询的表id=10数据是,这条数据就被锁定了,第一个人获得锁,后面的人只能等待第一个人完成事务提交后才能获得锁进行操作  


$this->db->begin(); // 开启事务

try{

  $info = $this->db->findOne("select * from table where id=1 FOR UPDATE ");

  sleep(5);

  $this->db->commit() // 只有提交后后面的请求才可以执行

} catch (\Exception $e) {

    $this->db->rollback()

}

2.乐观锁


为什么叫乐观锁?


默认每次的执行都不会发生并发,只有到真正执行变更的时候检测并发


原理是利用mysql update 原子性,也就是不论多少次并发,mysql update 只会一条一条的更新


例:


$this->db->begin(); //开启事务

try{

    $info = $this->db->findOne("select id,name,version from table where id=1");

    sleep(5);

    // 其他逻辑

    $version = $info['version'] + 1;

    // 主要防止并发在这里

    $this->db->excute("update set name='123', version=$version where version=$info['version'] and id=1 ");

    $this->db->commit()

} catch (\Exception $e) {

    $this->db->rollback()

}

3.redis锁


// 单个用户重复提交 场景

$hasLock = $this->redis->set($key . '用户唯一标识', 1, 'nx', 'ex', $expire);

if (!$hasLock) { // 没有获得锁

    throw new Exception('排队中请稍后...');

}

// 并发场景

$hasLock = $this->redis->set($key, 1, 'nx', 'ex', $expire);

if (!$hasLock) { // 没有获得锁

    throw new Exception(''排队中请稍后...');

}

sleep(5);

// 处理完业务 解锁

$this->redis->del($key);

4.redis队列


以上方法都不是真正意义上的并发,都是强制用户排队一个一个的来,而redis 队列可以实现真正的并发


根据具体业务的提前使用$this->redis->lpush(); 将需要并发的红包或者商品lpush入列,并发的时候lpop出列,因为lpop是原子性操作所以不会发生超卖或超领情况


5.其他


redis lua脚本、redis事务、MQ\KAFKA中间件 等