码迷,mamicode.com
首页 > Web开发 > 详细

PHP如何解决并发问题

时间:2016-08-05 15:13:01      阅读:153      评论:0      收藏:0      [点我收藏+]

标签:

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;

 

PHP如何解决并发问题

标签:

原文地址:http://www.cnblogs.com/sdgf/p/5740998.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!