PHP Concurrent Lock Case Analysis

Source: Internet
Author: User
Tags flock php source code
This article introduces the PHP concurrency lock example, to lock the data, only allow a user to operate within a time, this time need to use the lock, the need for friends to understand.

In the work project, you will encounter some PHP concurrent access to modify a data problem, if the data is not locked, it will cause data errors. Below I will analyze a financial payment lock problem. We hope to help you.

1 NO lock mechanism applied

1.1 Financial Payment Simplified version code

<!--? php/** * pay.php * * Pay no app lock * * Copy Right (c) * * Modification History: *--------------------* 2 016/9/10, by Clevercode, Create * *//user pays function Pay ($userId, $money) {if (false = = Is_int ($userId) | | false = is_in    T ($money)) {return false;}   Total withdrawal $total = Getuserleftmoney ($userId);  The cost is greater than the remaining if ($money--$total) {return false;   }//Balance $left = $total-$money; Update balance return Setuserleftmoney ($userId, $left); }//Remove the user's balance function Getuserleftmoney ($userId) {if (false = = Is_int ($userId)) {return 0;} $sql = "Select Account form Use   R_account where UserID = ${userid} "; $mysql = new MySQL ();//mysql database return $mysql->query ($sql);} Update user balance function Setuserleftmoney ($userId, $money) {if (false = = Is_int ($userId) | | false = = Is_int ($money)) {return false ;   } $sql = "Update user_account Set account = ${money} where UserID = ${userid}"; $mysql = new MySQL ();//mysql database return $mysql->execute ($sql);}? >

1.2 Problem Analysis

If there are two operators (P and M), the user number 100 accounts, respectively, in the PC and mobile phone terminal simultaneous landing, 100 of the total balance of the account has 1000,p operator Flower 200,m operator spent 300. The concurrency process is as follows.

P Operator:

    1. Remove the user's balance 1000.

    2. The remaining 800 after payment = 1000-200.

    3. Account balance 800 after update.

M operator:

    1. Remove the user balance 1000.

    2. The remaining 700 after payment = 1000-300.

    3. Account balance 700 after payment.

After two payments, the balance of the account is still 700, should be the case is spent 500, the balance of 500 of the account. The root cause of this phenomenon is that when concurrency occurs, both p and m balance data are 1000.

2 Plus lock design

The operation of the lock is generally only two steps, one acquires the lock (Getlock), and the other is the release lock (ReleaseLock). However, there are many ways of locking in reality, which can be implemented by means of files; SQL implementation; Memcache implementation; Based on this scenario, we consider using the policy model.

The 2.1 class diagram is designed as follows

2.2 PHP source code is designed as follows

locksystem.php

<!--? php/** * locksystem.php * * PHP lock mechanism * * Copy Right (c) * * * Modification History: *-------------------- * 2016/9/10, by Clevercode, Create * */class locksystem{const LOCK_TYPE_DB = ' Sqllock '; const Lock_type_file = ' FILE Lock ';   Const Lock_type_memcache = ' Memcachelock '; Private $_lock = null;    private static $_supportlocks = Array (' Filelock ', ' sqllock ', ' memcachelock '); Public function __construct ($type, $options = Array ()) {if (false = = Empty ($type)) {$this--->createlock ($type, $o  ptions);  }} Public Function Createlock ($type, $options =array ()) {if (false = = In_array ($type, self::$_supportlocks)) {throw  New Exception ("Not-support lock of ${type}"); } $this->_lock = new $type ($options); Public Function Getlock ($key, $timeout = Ilock::expire) {if (false = = $this->_lock instanceof ILock) {throw     New Exception (' false = = $this->_lock instanceof ILock ');  } $this->_lock->getlock ($key, $timeout); } public functionReleaseLock ($key) {if (false = = $this->_lock instanceof ILock) {throw new Exception (' false = = $this->_lock in     Stanceof ILock ');    } $this->_lock->releaselock ($key); }}interface ilock{Const EXPIRE = 5; Public function Getlock ($key, $timeout =self::expire); public Function ReleaseLock ($k EY);}  Class Filelock implements ilock{private $_fp; private $_single; Public function __construct ($options) {if (Isset ($options [' path ')] && is_dir ($options [' path ']) {$this->_ Lockpath = $options [' path ']. '  /';  } else {$this->_lockpath = '/tmp/'; } $this->_single = Isset ($options [' single '])? $options [' Single ']:false;   Public Function Getlock ($key, $timeout =self::expire) {$startTime = Timer::gettimestamp ();  $file = MD5 (__file__. $key); $this-&GT;FP = fopen ($this->_lockpath. $file.  Lock ', "w+");  if (true | | $this->_single) {$op = lock_ex + lock_nb;  } else {$op = LOCK_EX; } if (false = = Flock ($this->fp, $op, $a)) {throw nEW Exception (' failed '); } return true;  Public Function ReleaseLock ($key) {flock ($this->fp, Lock_un); Fclose ($this-&GT;FP);  }} class Sqllock implements ilock{Public function __construct ($options) {$this->_db = new MySQL ();  The Public Function Getlock ($key, $timeout =self::expire) {$sql = "select Get_lock ('". $key. "', '". $timeout. "')";  $res = $this->_db->query ($sql); return $res;  The Public Function ReleaseLock ($key) {$sql = "select Release_lock ('". $key. "')"; return $this->_db->query ($sql);   }} class Memcachelock implements ilock{Public function __construct ($options) {$this->memcache = new Memcache ();}  Public Function Getlock ($key, $timeout =self::expire) {$waitime = 20000;  $totalWaitime = 0;  $time = $timeout *1000000;    while ($totalWaitime < $time && false = = $this->memcache->add ($key, 1, $timeout)) {usleep ($waitime);  $totalWaitime + = $waitime; } if ($totalWaitime >= $time) throw new Exception (' Can not getLock for waiting '. $timeout. ' s. '); } Public Function ReleaseLock ($key) {$this->memcache->delete ($key);}}

3 Application lock mechanism

3.1 Payment System Application lock

<!--? php/** * pay.php * * Pay App Lock * * Copy Right (c) * * * Modification History: *--------------------* 201 6/9/10, by Clevercode, Create * *//user pays function Pay ($userId, $money) {if (false = = Is_int ($userId) | | false = Is_int (    $money)) {return false;}         try {//Create lock (recommended with memcachelock) $lockSystem = new Locksystem (Locksystem::lock_type_memcache);  Get lock $lockKey = ' pay '. $userId;     $lockSystem--->getlock ($lockKey, 8);     Total withdrawal $total = Getuserleftmoney ($userId);   The cost is greater than the remaining if ($money > $total) {$ret = false;       } else {//Balance $left = $total-$money;  Update Balance $ret = Setuserleftmoney ($userId, $left);  }//Release lock $lockSystem->releaselock ($lockKey);   } catch (Exception $e) {//Release lock $lockSystem->releaselock ($lockKey); }//Remove the user's balance function Getuserleftmoney ($userId) {if (false = = Is_int ($userId)) {return 0;} $sql = "Select Account Form US   Er_account where UserID = ${userid} "; $mysql = new MySQL ();//mysql database return $mysql->qUery ($sql);} Update user balance function Setuserleftmoney ($userId, $money) {if (false = = Is_int ($userId) | | false = = Is_int ($money)) {return false ;   } $sql = "Update user_account Set account = ${money} where UserID = ${userid}"; $mysql = new MySQL ();//mysql database return $mysql->execute ($sql);}? >

3.2 Lock Analysis

P Operator:

    1. Get Lock: pay100

    2. Remove the user's balance 1000.

    3. The remaining 800 after payment = 1000-200.

    4. Account balance 800 after update.

    5. Release Lock: pay100

M operator:

    1. Wait Lock: pay100

    2. Get Lock: pay100

    3. Get Balance: 800

    4. The remaining 500 after payment = 800-300.

    5. Account balance 500 after payment.

    6. Release Lock: pay100

After two payments, the balance is 500. It's perfect. The access problem of critical zone resource caused by concurrency is solved.

Summary: The above is the entire content of this article, I hope to be able to help you learn.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.