使用php實現並發鎖控制(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

}

php 使用redis鎖限制並發訪問類示例

本文介紹了php

使用redis鎖限制並發訪問類,並詳細的介紹了並發訪問限制方法。

1.並發訪問限制問題

對於一些需要限制同一個用戶並發訪問的場景,如果用戶並發請求多次,而服務器處理沒有加鎖限制,用戶則可以多次請求成功。

例如換領優惠券,如果用戶同一時間並發提交換領碼,在沒有加鎖限制的情況下,用戶則可以使用同一個換領碼同時兌換到多張優惠券。

偽代碼如下:

if

A(可以換領)

B(執行換領)

C(更新為已換領)

D(結束)

如果用戶並發提交換領碼,都能通過可以換領(A)的判斷,因為必須有一個執行換領(B)後,才會更新為已換領(C)。因此如果用戶在有一個更新為已換領之前,有多少次請求,這些請求都可以執行成功。

2.並發訪問限制方法

使用文件鎖可以實現並發訪問限制,但對於分布式架構的環境,使用文件鎖不能保證多台服務器的並發訪問限制。

Redis是一個開源的使用ANSI

C語言編寫、支持網絡、可基於內存亦可持久化的日誌型、Key-Value數據庫,並提供多種語言的API。

本文將使用其setnx方法實現分布式鎖功能。setnx即Set

it

N**ot

eX**ists。

當鍵值不存在時,插入成功(獲取鎖成功),如果鍵值已經存在,則插入失敗(獲取鎖失敗)

RedisLock.class.PHP

?php

/**

*

Redis鎖操作類

*

Date:

2016-06-30

*

Author:

fdipzone

*

Ver:

1.0

*

*

Func:

*

public

lock

獲取鎖

*

public

unlock

釋放鎖

*

private

connect

連接

*/

class

RedisLock

{

//

class

start

private

$_config;

private

$_redis;

/**

*

初始化

*

@param

Array

$config

redis連接設定

*/

public

function

__construct($config=array()){

$this-_config

=

$config;

$this-_redis

=

$this-connect();

}

/**

*

獲取鎖

*

@param

String

$key

鎖標識

*

@param

Int

$expire

鎖過期時間

*

@return

Boolean

*/

public

function

lock($key,

$expire=5){

$is_lock

=

$this-_redis-setnx($key,

time()+$expire);

//

不能獲取鎖

if(!$is_lock){

//

判斷鎖是否過期

$lock_time

=

$this-_redis-get($key);

//

鎖已過期,刪除鎖,重新獲取

if(time()$lock_time){

$this-unlock($key);

$is_lock

=

$this-_redis-setnx($key,

time()+$expire);

}

}

return

$is_lock?

true

:

false;

}

/**

*

釋放鎖

*

@param

String

$key

鎖標識

*

@return

Boolean

*/

public

function

unlock($key){

return

$this-_redis-del($key);

}

/**

*

創建redis連接

*

@return

Link

*/

private

function

connect(){

try{

$redis

=

new

Redis();

$redis-connect($this-_config[‘host’],$this-_config[‘port’],$this-_config[‘timeout’],$this-_config[‘reserved’],$this-_config[‘retry_interval’]);

if(empty($this-_config[‘auth’])){

$redis-auth($this-_config[‘auth’]);

}

$redis-select($this-_config[‘index’]);

}catch(RedisException

$e){

throw

new

Exception($e-getMessage());

return

false;

}

return

$redis;

}

}

//

class

end

?

demo.php

?php

require

‘RedisLock.class.php’;

$config

=

array(

‘host’

=

‘localhost’,

‘port’

=

6379,

‘index’

=

0,

‘auth’

=

”,

‘timeout’

=

1,

‘reserved’

=

NULL,

‘retry_interval’

=

100,

);

//

創建redislock對象

$oRedisLock

=

new

RedisLock($config);

//

定義鎖標識

$key

=

‘mylock’;

//

獲取鎖

$is_lock

=

$oRedisLock-lock($key,

10);

if($is_lock){

echo

‘get

lock

successbr’;

echo

‘do

sth..br’;

sleep(5);

echo

‘successbr’;

$oRedisLock-unlock($key);

//

獲取鎖失敗

}else{

echo

‘request

too

frequentlybr’;

}

?

測試方法:

打開兩個不同的瀏覽器,同時在A,B中訪問demo.php

如果先訪問的會獲取到鎖

輸出

get

lock

success

do

sth..

success

另一個獲取鎖失敗則會輸出request

too

frequently

保證同一時間只有一個訪問有效,有效限制並發訪問。

為了避免系統突然出錯導致死鎖,所以在獲取鎖的時候增加一個過期時間,如果已超過過期時間,即使是鎖定狀態都會釋放鎖,避免死鎖導致的問題。

源碼下載地址:點擊查看

PHP開發中解決並發問題的幾種實現方法分析

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

flock函數用於獲取文件的鎖,這個鎖同時只能被一個線程獲取到,其它沒有獲取到鎖的線程要麼阻塞,要麼獲取失敗

在獲取到鎖的時候,先查詢庫存,如果庫存大於0,則進行下訂單操作,減庫存,然後釋放鎖

方案二:使用隊列

將用戶的下單請求依次存入一個隊列中,後台用一個單獨的進程處理隊列中的下單請求

PHP如何使用文件鎖解決高並發問題

?php

//連接數據庫

$con=mysqli_connect(“192.168.2.186″,”root”,”root”,”test”);

//查詢商品數量是否大於0,大於0才能下單,並減少庫存

$fp = fopen(“lock.txt”, “r”);

//加鎖

if(flock($fp,LOCK_EX))

{

$res=mysqli_fetch_assoc(mysqli_query($con,’SELECT total FROM shop WHERE id=1 LIMIT 1′));

if($res[‘total’]0){mysqli_query($con,’UPDATE shop SET total=total-1 WHERE id=1′);}

//執行完成解鎖

flock($fp,LOCK_UN);

}

//關閉文件

fclose($fp);

unset($res);

mysqli_close($con);

?

原創文章,作者:PAZAX,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/128622.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
PAZAX的頭像PAZAX
上一篇 2024-10-03 23:25
下一篇 2024-10-03 23:25

相關推薦

  • PHP和Python哪個好找工作?

    PHP和Python都是非常流行的編程語言,它們被廣泛應用於不同領域的開發中。但是,在考慮擇業方向的時候,很多人都會有一個問題:PHP和Python哪個好找工作?這篇文章將從多個方…

    編程 2025-04-29
  • PHP怎麼接幣

    想要在自己的網站或應用中接受比特幣等加密貨幣的支付,就需要對該加密貨幣擁有一定的了解,並使用對應的API進行開發。本文將從多個方面詳細闡述如何使用PHP接受加密貨幣的支付。 一、環…

    編程 2025-04-29
  • 使用PHP foreach遍歷有相同屬性的值

    本篇文章將介紹如何使用PHP foreach遍歷具有相同屬性的值,並給出相應的代碼示例。 一、基礎概念 在講解如何使用PHP foreach遍歷有相同屬性的值之前,我們需要先了解幾…

    編程 2025-04-28
  • PHP獲取301跳轉後的地址

    本文將為大家介紹如何使用PHP獲取301跳轉後的地址。301重定向是什麼呢?當我們訪問一個網頁A,但是它已經被遷移到了另一個地址B,此時若服務器端做了301重定向,那麼你的瀏覽器在…

    編程 2025-04-27
  • PHP登錄頁面代碼實現

    本文將從多個方面詳細闡述如何使用PHP編寫一個簡單的登錄頁面。 1. PHP登錄頁面基本架構 在PHP登錄頁面中,需要包含HTML表單,用戶在表單中輸入賬號密碼等信息,提交表單後服…

    編程 2025-04-27
  • PHP與Python的比較

    本文將會對PHP與Python進行比較和對比分析,包括語法特性、優缺點等方面。幫助讀者更好地理解和使用這兩種語言。 一、語法特性 PHP語法特性: <?php // 簡單的P…

    編程 2025-04-27
  • PHP版本管理工具phpenv詳解

    在PHP項目開發過程中,我們可能需要用到不同版本的PHP環境來試驗不同的功能或避免不同版本的兼容性問題。或者我們需要在同一台服務器上同時運行多個不同版本的PHP語言。但是每次手動安…

    編程 2025-04-24
  • PHP數組去重詳解

    一、array_unique函數 array_unique是php中常用的數組去重函數,它基於值來判斷元素是否重複,具體使用方法如下: $array = array(‘a’, ‘b…

    編程 2025-04-24
  • PHP導出Excel文件

    一、PHP導出Excel文件列寬調整 當我們使用PHP導出Excel文件時,有時需要調整單元格的列寬。可以使用PHPExcel類庫中的setWidth方法來設置單元格的列寬。下面是…

    編程 2025-04-24
  • php擴展庫初探

    一、什麼是php擴展庫? PHP擴展庫(PHP extension)是一些用C語言編寫的動態鏈接庫,用於擴展PHP的功能。PHP擴展庫使得PHP可以與各種數據庫系統相連、SMTP、…

    編程 2025-04-23

發表回復

登錄後才能評論