PHP解决并发问题的几种实现

对于商品抢购等并发场景下,可能会出现超卖的现象,这时就需要解决并发所带来的这些问题了

在PHP语言中并没有原生的提供并发的解决方案,因此就需要借助其他方式来实现并发控制。

方案一:使用文件锁排它锁

flock函数用于获取文件的锁,这个锁同时只能被一个线程获取到,其它没有获取到锁的线程要么阻塞,要么获取失败

在获取到锁的时候,先查询库存,如果库存大于0,则进行下订单操作,减库存,然后释放锁

方案二:使用MySQL数据库提供的悲观锁

Innodb存储引擎支持行级锁,当某行数据被锁定时,其他进程不能对这行数据进行操作

先查询并锁定行:select stock_num from table where id=1 for update

if(stock_num > 0){

//下订单

update table set stock_num=stock-1 where id=1

}

方案三:使用队列

将用户的下单请求依次存入一个队列中,后台用一个单独的进程处理队列中的下单请求

方案四:使用Redis

redis的操作都是原子性的,可以将商品的库存存入redis中,下单之前对库存进行decr操作,如果返回的值大于等于0等可以下单,否则不能下单,这种方式效率较高

if(redis->get(‘stock_num‘) > 0){

stock_num = redis->decr(‘stock_num‘)

if(stock_num >= 0){

//下订单

}else{

//库存不足

}

}else{

//库存不足

}

其他并发问题:

在现实应用中,很多情况下会把数据存入缓存,当缓存失效时,去数据库取数据并重新设置缓存,如果这时并发量很大,会有很多进程同时去数据库取数据,导致很多请求

穿透到数据库,而使数据库奔溃,这里可用文件锁来解决

 1     $data = $cache->get(‘key‘);
 2     if(!$data){
 3         $fp = fopen(‘lockfile‘);
 4         if(flock($fp, LOCK_EX)){
 5             $data = $cache->get(‘key‘);//拿到锁后再次检查缓存,这时可能已经有了
 6             if(!$data){
 7                 $data = mysql->query();
 8                 $cache->set(‘key‘, $data);
 9             }
10             flock($fp, LOCK_UN);
11         }
12         fclose($fp);
13     }  

说白了,要解决并发问题就必须要加锁,各种方案的本质都是加锁

时间: 2024-10-29 19:11:00

PHP解决并发问题的几种实现的相关文章

EntityFramework Core解决并发详解

话题(EntityFramework Core并发) 对于并发问题这个话题相信大家并不陌生,当数据量比较大时这个时候我们就需要考虑并发,对于并发涉及到的内容也比较多,在EF Core中我们将并发分为几个小节来陈述,让大家看起来也不太累,也容易接受,我们由浅入深.首先我们看下给出的Blog实体类.     public class Blog : IEntityBase     {        public int Id { get; set; }        public string Nam

乐观锁与悲观锁——解决并发问题(转)

引言 为什么需要锁(并发控制)? 在多用户环境中,在同一时间可能会有多个用户更新相同的记录,这会产生冲突.这就是著名的并发性问题. 典型的冲突有: 丢失更新:一个事务的更新覆盖了其它事务的更新结果,就是所谓的更新丢失.例如:用户A把值从6改为2,用户B把值从2改为6,则用户A丢失了他的更新. 脏读:当一个事务读取其它完成一半事务的记录时,就会发生脏读取.例如:用户A,B看到的值都是6,用户B把值改为2,用户A读到的值仍为6. 为了解决这些并发带来的问题. 我们需要引入并发控制机制. 并发控制机制

乐观锁与悲观锁——解决并发问题

悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁.传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁. 乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制.乐观锁适用于

(转)乐观锁与悲观锁——解决并发问题

引言 为什么需要锁(并发控制)? 在多用户环境中,在同一时间可能会有多个用户更新相同的记录,这会产生冲突.这就是著名的并发性问题. 典型的冲突有: 丢失更新:一个事务的更新覆盖了其它事务的更新结果,就是所谓的更新丢失.例如:用户A把值从6改为2,用户B把值从2改为6,则用户A丢失了他的更新. 脏读:当一个事务读取其它完成一半事务的记录时,就会发生脏读取.例如:用户A,B看到的值都是6,用户B把值改为2,用户A读到的值仍为6. 为了解决这些并发带来的问题. 我们需要引入并发控制机制. 并发控制机制

构建高性能服务(二)java高并发锁的3种实现

构建高性能服务(二)java高并发锁的3种实现 来源:http://www.xymyeah.com/?p=46 提高系统并发吞吐能力是构建高性能服务的重点和难点.通常review代码时看到synchronized是我都会想一想,这个地方可不可以优化.使用synchronized使得并发的线程变成顺序执行,对系统并发吞吐能力有极大影响,我的博文 http://maoyidao.iteye.com/blog/1149015 介绍了可以从理论上估算系统并发处理能力的方法. 那么对于必须使用synchr

PHP如何解决并发问题

PHP如何解决并发问题 有个问题: 一个进程开启事务对表的某一行做了修改,但还没有提交,另一个进程查询该行数据,获取到的是原始的,这时候上面的事物提交了,我再用这个原始数据的时候就有问题…… 那我们该怎么解决这个问题呢? 1.文件锁 如果对该表的更新或插入只有一个文件,这种方式是可以解决的 实现方式如下: public static function cbInventoryReserve() { $LOCK_FILE_PATH = $_SERVER['DOCUMENT_ROOT']."wmsin

构造并发程序的三种基本方法和优缺点

构造并发程序的三种基本方法 进程 用这种方法,每个逻辑控制流都是一个进程,由内核来调度维护.因为进程有独立的虚拟地址空间,想要和其他流通信,控制流必须使用某种显式的进程间通信机制. I/O多路复用 在这种形式的并发编程中,应用程序在一个进程的上下文中显式地调度它们自己的逻辑流.逻辑流被模型化为状态机,数据到达文件描述符后,主程序显式地从一个状态转换到另一个状态.因为程序是一个单独的进程,所以所有的流都共享同一个地址空间. 假设要求编写一个echo服务器,它也能对用户从标准输入键入的交互命令做出响

锁是用来解决并发问题

共享锁,又称为读锁,获得共享锁之后,可以查看但无法修改和删除数据. 排他锁,又称为写锁.独占锁,获得排他锁之后,既能读数据,又能修改数据. 为什么要加锁 很多人都知道,锁是用来解决并发问题的,那么什么是并发问题呢?并发情况下,不加锁会有什么问题呢? 拿生活中的洗手间举例子,每个洗手间都会有一个门,并且是可以上锁的,当我们进入洗手间之后会把门反锁,当我们出来之后再把锁打开. 当门被锁上之后,其他人只能在门外等待.洗手间之所以要有门锁,就是为了保护隐私的,避免出现多个人同时进入洗手间的情况. 这和数

解决线程安全的三种方法

1:线程安全 如果有多个线程在同时运行,而这些线程可能会同时运行这段代码.程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的. 我们通过一个案例,演示线程的安全问题: 电影院要卖票,我们模拟电影院的卖票过程.假设要播放的电影是 “上海堡垒”,本次电影的座位共50个(只能卖50张票). 我们来模拟电影院的售票窗口,实现多个窗口同时卖 “葫芦娃大战奥特曼”这场电影票(多个窗口一起卖这50张票)需要窗口,采用线程对象来模拟:需要票,Runnable接口子类