php并发解决方案


事务不能解决并发,只能保证在一个事务内所有操作的一致性

 常见的并发处理如下:

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事务、中间件 等

 

 

 

 

 

 

 

 

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM