PHP如何解决并发问题

PHP如何解决并发问题

有个问题:

一个进程开启事务对表的某一行做了修改,但还没有提交,另一个进程查询该行数据,获取到的是原始的,这时候上面的事物提交了,我再用这个原始数据的时候就有问题……

那我们该怎么解决这个问题呢?

1、文件锁

如果对该表的更新或插入只有一个文件,这种方式是可以解决的

实现方式如下:

public static function cbInventoryReserve() {
        $LOCK_FILE_PATH = $_SERVER[‘DOCUMENT_ROOT‘]."wmsinventoryapi/inventory/InventoryReserve.php";
        $fp = fopen( $LOCK_FILE_PATH, "r" );
        if (!$fp) {
            die("Failed to open the lock file!");
        }
        flock ( $fp, LOCK_EX );

    //需要进行的操作
        $params = Flight::request()->getBody();
        $params = json_decode($params, true);
        if (! is_array($params) || empty($params)) {
            Flight::sendRouteResult(array("error_code" => "40002","error_info" => "params empty"));
        }
        $result = \Inventory\InventoryEngine::getInstance()->inventoryReserve($params);

        flock ( $fp, LOCK_UN );
        fclose ( $fp );
        Flight::sendRouteResult($result);
    }

  函数说明  flock()会依参数operation所指定的方式对参数fd所指的文件做各种锁定或解除锁定的动作。此函数只能锁定整个文件,无法锁定文件的某一区域。

   参数  operation有下列四种情况:

   LOCK_SH 建立共享锁定。多个进程可同时对同一个文件作共享锁定。

  LOCK_EX 建立互斥锁定。一个文件同时只有一个互斥锁定。

  LOCK_UN 解除文件锁定状态。

   LOCK_NB 无法建立锁定时,此操作可不被阻断,马上返回进程。通常与LOCK_SH或LOCK_EX 做OR(|)组合。

   单一文件无法同时建立共享锁定和互斥锁定,而当使用dup()或fork()时文件描述词不会继承此种锁定。

   返回值  返回0表示成功,若有错误则返回-1,错误代码存于errno。

换言之:

使用共享锁LOCK_SH,如果是读取,不需要等待,但如果是写入,需要等待读取完成。

使用独占锁LOCK_EX,无论写入/读取都需要等待。

LOCK_UN,无论使用共享/读占锁,使用完后需要解锁。

LOCK_NB,当被锁定时,不阻塞,而是提示锁定。

为了更好的移植性,对于文件的打开与关闭我选择了fopen和fclose的组合,但flock的第一个参数要求的是int类型的文件描述符。这里对fopen返回的FILE类型的文件指针进行转换,转换为int型的文件描述符 (假设open函数返回的文件描述符为fd,而fopen返回的文件指针为*fp,则fd等价于fp->_fileno).

2、序列化接口(对象序列化)

所有php里面的值都可以使用函数serialize()来返回一个包含字节流的字符串来表示。unserialize()函数能够重新把字符串变回php原来的值。 序列化一个对象将会保存对象的所有变量,但是不会保存对象的方法,只会保存类的名字。

<?php
// classa.inc:

  class A {
      public $one = 1;

      public function show_one() {
          echo $this->one;
      }
  }

// page1.php:

  include("classa.inc");

  $a = new A;
  $s = serialize($a);
  // 把变量$s保存起来以便文件page2.php能够读到
  file_put_contents(‘store‘, $s);

// page2.php:

  // 要正确了解序列化,必须包含下面一个文件
  include("classa.inc");

  $s = file_get_contents(‘store‘);
  $a = unserialize($s);

  // 现在可以使用对象$a里面的函数 show_one()
  $a->show_one();
?>

3、select *** for update

Select …forupdate语句是我们经常使用手工加锁语句。通常情况下,select语句是不会对数据加锁,妨碍影响其他的DML和DDL操作。同时,在多版本一致读机制的支持下,select语句也不会被其他类型语句所阻碍。

借助for update子句,我们可以在应用程序的层面手工实现数据加锁保护操作。

for update子句的默认行为就是自动启动一个事务,借助事务的锁机制将数据进行锁定。

开启一个事务使用for update

start transaction;

select sum(quantity) from ws_inventory_item where inventory_item_id=86 for update;

再开启另一个事务时,做update 操作的时,只能等待上面的事务,commit才能执行;

start transaction;

update ws_inventory_item set quantity = quantity + 1  where inventory_item_id = 86;
时间: 2024-10-17 12:42:29

PHP如何解决并发问题的相关文章

SQL锁表解决并发性

在数据库开发过程中,不得不考虑并发性的问题,因为很有可能当别人正在更新表中记录时,你又从该表中读数据,那你读出来的数据有可能就不是你希望得到的数据.可以说有些数据同时只能有一个事物去更新,否则最终显示给用户的数据不是数据库中现存的数据.锁表就限制不同的事物在同一时间内不允许同时操作一张表,实例很简单,可以用select来锁定整张表,那别人就不可能更新或是读取表的记录.select * from dbo.Employee with(holdlock); with关键字来设置锁表的方式.下面是wit

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. 为了解决这些并发带来的问题. 我们需要引入并发控制机制. 并发控制机制

网络编程三---多线程/进程解决并发问题

前文列出的代码给大家展示了一个最简单的网络程序,但正如文章末尾所提的,这个最简单的网络程序最大的缺点是服务端一次只能服务一个客户端,就比如说你去吃饭,饭店只有一个服务员, 而且服务员在客户离开之前只能为一个客户服务,也就是说你只能等待你前面的客户吃好饭离开了,然后你才能进去吃饭,而在你吃饭的时候时候,你后面来的人都得等你吃完饭才能轮到你后面一个人吃饭.这种模式的缺点很明显,因为在你进去点好菜到买单前的这段时间,这个服务员都是空闲的,为什么不让服务员在这个空闲时间让其他客户进来服务员为他点菜呢?在

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

对于商品抢购等并发场景下,可能会出现超卖的现象,这时就需要解决并发所带来的这些问题了 在PHP语言中并没有原生的提供并发的解决方案,因此就需要借助其他方式来实现并发控制. 方案一:使用文件锁排它锁 flock函数用于获取文件的锁,这个锁同时只能被一个线程获取到,其它没有获取到锁的线程要么阻塞,要么获取失败 在获取到锁的时候,先查询库存,如果库存大于0,则进行下订单操作,减库存,然后释放锁 方案二:使用MySQL数据库提供的悲观锁 Innodb存储引擎支持行级锁,当某行数据被锁定时,其他进程不能对

list的迭代器能解决并发问题,collection 的迭代器不能解决并发问题,for可以解决并发问题

list的迭代器能解决并发问题,collection 的迭代器不能解决并发问题 为什么list支持add,collection不支持 例如有两个人同时添加第三个元素 list的迭代器能锁定线程 只有等第一人添加完成才能进行第二个人添加 而 collection的迭代器却不具备这样的功能   .动态不确定性! 为什么add,collection都支持remove呢  因为位置已经被占了 固定了 就算两个人同时删除也没事 第一个人删除有元素 ,第二个人删的是空值 原文地址:https://www.c

python单线程解决并发

1.单线程解决并发 方式一 import socket import select # 百度创建连接:非阻塞 client1 = socket.socket() client1.setblocking(False) try: client1.connect(('www.baidu.com', 80)) except BlockingIOError as e: pass # 搜狗创建连接:非阻塞 client2 = socket.socket() client2.setblocking(False