Php concurrent lock examples and php concurrent examples

Source: Internet
Author: User

Php concurrent lock examples and php concurrent examples

In the work project, you may encounter some php concurrent access to modify a data problem. If the data is not locked, it will cause a data error. Next I will analyze a financial payment lock problem. Hope to help you.

1. No application lock mechanism

1.1 simplified financial payment version code

<! --? Php/*** pay. php ** payment does not apply the lock ** Copy right (c) 2016 ** modification history: * ------------------ * 2016/9/10, by CleverCode, create ** // user payment function pay ($ userId, $ money) {if (false = is_int ($ userId) | false = is_int ($ money )) {return false;} // total amount retrieved $ total = getUserLeftMoney ($ userId); // if ($ money --> $ total) {return false ;} // balance $ left = $ total-$ money; // update balance return setUserLeftM Oney ($ userId, $ left) ;}// retrieve the user's Balance function getUserLeftMoney ($ userId) {if (false = is_int ($ userId) {return 0 ;} $ SQL = "select account form user_account where userid =$ {userId}"; // $ mysql = new mysql (); // mysql database return $ mysql-> query ($ SQL);} // update the user balance function setUserLeftMoney ($ userId, $ money) {if (false = is_int ($ userId) | false = is_int ($ money) {return false;} $ SQL = "update user_account set Ccount =$ {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), log on to the pc and mobile phone respectively with the user ID 100. The total account balance is 100, and the p operator spends 1000, m operator costs 300. The concurrency process is as follows.

P OPERATOR:

  1. Obtain the user's balance of 1000.
  2. Remaining 800 after payment = 1000-200.
  3. The updated account balance is 800.

M OPERATOR:

  1. Take out the user balance of 1000.
  2. Remaining 700 after payment = 1000-300.
  3. After payment, the account balance is 700.

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

2 Lock Design

The lock operation generally takes only two steps: getLock and releaseLock ). There are many methods to implement real locks, such as file implementation, SQL implementation, and Memcache implementation. In this scenario, we consider using the Policy mode.

2.1 class diagram design:

2.2 php source code design:

LockSystem. php

<! --? Php/*** LockSystem. php ** php lock mechanism ** Copy right (c) 2016 ** modification history: * ------------------ * 2016/9/10, by CleverCode, create **/class LockSystem {const LOCK_TYPE_DB = 'sqllock'; const LOCK_TYPE_FILE = 'filelock '; const LOCK_TYPE_MEMCACHE = 'memcachelock'; private $ _ lock = null; private static $ _ supportLocks = array ('filelock ', 'sqllock', 'memcachelock'); public function _ const Ruct ($ type, $ options = array () {if (false = empty ($ type) {$ this ---> createLock ($ type, $ options );}} 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 I Lock) {throw new Exception ('false = $ this-> _ lock instanceof ilock');} $ this-> _ lock-> getLock ($ key, $ timeout);} public function releaseLock ($ key) {if (false = $ this-> _ lock instanceof ILock) {throw new Exception ('false ==this this-> _ lock instanceof ilock');} $ this-> _ lock-> releaseLock ($ key );}} interface ILock {const EXPIRE = 5; public function getLock ($ key, $ timeout = self: EXPIRE); public functio N releaseLock ($ key);} 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-> 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-> fp );}} class SQLLock implements ILock {public function _ construct ($ options) {$ this-> _ db = new mysql ();} public function getLock ($ key, $ timeout = self:: EXPIRE) {$ SQL = "SELECT GET_LOCK ('". $ key. "','". $ timeout. "')"; $ res = $ this-> _ db-> query ($ SQL); return $ res;} 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 get lock for waiting '. $ timeout. 's. ');} public function releaseLock ($ key) {$ this-> memcache-> delete ($ key );}}

3 apply the lock mechanism

3.1 payment system application lock

<! --? Php/*** pay. php ** payment application lock ** Copy right (c) 2016 ** modification history: * ------------------ * 2016/9/10, by CleverCode, create ** // user payment function pay ($ userId, $ money) {if (false = is_int ($ userId) | false = is_int ($ money )) {return false;} try {// create a lock (MemcacheLock is recommended) $ lockSystem = new LockSystem (LockSystem: LOCK_TYPE_MEMCACHE); // obtain the lock $ lockKey = 'pay '. $ userId; $ lockSystem ---> getLock ($ lo CkKey, 8); // get the total $ total = getUserLeftMoney ($ userId); // if ($ money >$ total) {$ ret = false ;} else {// balance $ left = $ total-$ money; // update balance $ ret = setUserLeftMoney ($ userId, $ left );} // release the lock $ lockSystem-> releaseLock ($ lockKey);} catch (Exception $ e) {// release the lock $ lockSystem-> releaseLock ($ lockKey );}} // retrieve the user's Balance function getUserLeftMoney ($ userId) {if (false = is_int ($ userId) {return 0 ;}$ SQL = "select Account form user_account where userid =$ {userId} "; // $ mysql = new mysql (); // mysql database return $ mysql-> query ($ SQL );} // update the 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. Obtain the user's balance of 1000.
  3. Remaining 800 after payment = 1000-200.
  4. The updated account balance is 800.
  5. Release lock: pay100

M OPERATOR:

  1. Lock waiting: pay100
  2. Get lock: pay100
  3. Obtain balance: 800
  4. Remaining 500 after payment = 800-300.
  5. After payment, the account balance is 500.
  6. Release lock: pay100

After two payments, the balance is 500. It perfectly solves the problem of resource access in the critical section caused by concurrency.

Thank you for reading this article. I hope it will help you. Thank you for your support for this site!

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.