您的位置:

使用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);

?