redis mysql高并发_如何利用Redis锁解决高并发问题,看完就知道Redis是有多好用了...

原标题:如何利用Redis锁解决高并发问题,看完就知道Redis是有多好用了

图书推荐

这里我们主要利用Redis的setnx的命令来处理高并发。

setnx 有两个参数。第一个参数表示键。第二个参数表示值。如果当前键不存在,那么会插入当前键,将第二个参数做为值。返回 1。如果当前键存在,那么会返回0。

创建库存表

CREATETABLE`storage`(

`id`int( 11) unsignedNOTNULLAUTO_INCREMENT,

`number`int( 11) DEFAULTNULL,

PRIMARY KEY( `id`)

) ENGINE= InnoDBAUTO_INCREMENT= 1DEFAULTCHARSET=latin1

设置初始库存为10

创建订单表

CREATETABLE`order`(

`id`int( 11) unsignedNOTNULLAUTO_INCREMENT,

`number`int( 11) DEFAULTNULL,

PRIMARY KEY( `id`)

) ENGINE= InnoDBAUTO_INCREMENT= 1DEFAULTCHARSET=latin1

测试不用锁的时候

$pdo = newPDO( 'mysql:host=127.0.0.1;dbname=test', 'root', 'root');

$sql= "select `number` from storage where id=1 limit 1";

$res = $pdo->query($sql)->fetch();

$number = $res[ 'number'];

if($number> 0)

{

$sql = "insert into `order` VALUES (null,$number)";

$order_id = $pdo->query($sql);

if($order_id)

{

$sql= "update storage set `number`=`number`-1 WHERE id=1";

$pdo->query($sql);

}

}

ab测试模拟并发,发现库存是正确的。

mysql> select* from storage;

+ ----+--------+

| id | number |

+ ----+--------+

| 1| 0|

+ ----+--------+

1row inset ( 0.00sec)

在来看订单表

mysql> select * from `order`;

+----+--------+

| id |number |

+----+--------+

|1| 10 |

| 2 |10|

|3| 9 |

| 4 |7|

|5| 6 |

| 6 |5|

|7| 5 |

| 8 |5|

|9| 4 |

| 10 |1|

+----+--------+

10 rows inset (0.00 sec)

发现存在几个订单都是操作的同一个库存数据,这样就可能引起超卖的情况。

修改代码加入redis锁进行数据控制

/**

* Created by PhpStorm.

* User: daisc

* Date: 2018/7/23

* Time: 14:45

*/

classLock

{

privatestatic$_instance ;

private$_redis;

privatefunction__construct()

{

$this->_redis = newRedis();

$this->_redis ->connect('127.0.0.1');

}

publicstaticfunctiongetInstance()

{

if(self::$_instance instanceof self)

{

returnself::$_instance;

}

returnself::$_instance = newself();

}

/**

* @function加锁

* @param$key 锁名称

* @param$expTime 过期时间

*/

publicfunctionset($key,$expTime)

{

//初步加锁

$isLock = $this->_redis->setnx($key,time()+$expTime);

if($isLock)

{

returntrue;

}

else

{

//加锁失败的情况下。判断锁是否已经存在,如果锁存在切已经过期,那么删除锁。进行重新加锁

$val = $this->_redis->get($key);

if($val&&$val

{

$this->del($key);

}

return$this->_redis->setnx($key,time()+$expTime);

}

}

/**

* @param$key 解锁

*/

publicfunctiondel($key)

{

$this->_redis->del($key);

}

}

$pdo = newPDO('mysql:host=127.0.0.1;dbname=test', 'root', 'root');

$lockObj = Lock::getInstance();

//判断是能加锁成功

if($lock = $lockObj->set('storage',10))

{

$sql="select `number` from storage where id=1 limit 1";

$res = $pdo->query($sql)->fetch();

$number = $res['number'];

if($number>0)

{

$sql ="insert into `order` VALUES (null,$number)";

$order_id = $pdo->query($sql);

if($order_id)

{

$sql="update storage set `number`=`number`-1 WHERE id=1";

$pdo->query($sql);

}

}

//解锁

$lockObj->del('storage');

}

else

{

//加锁不成功执行其他操作。

}

再次进行ab测试,查看测试结果

mysql> select * from `order`;

+----+--------+

| id |number |

+----+--------+

|1| 10 |

| 2 |9|

|3| 8 |

| 4 |7|

|5| 6 |

| 6 |5|

|7| 4 |

| 8 |3|

|9| 2 |

| 10 |1|

+----+--------+

10 rows inset (0.00 sec)

发现订单表没有操作同一个库存数据的情况。所以利用redis锁是可以有效的处理高并发的。

这里在加锁的时候其实是可以不需要判断过期时间的,这里我们为了避免造成死锁,所以加一个过期时间的判断。当过期的时候主动删除该锁。返回搜狐,查看更多

责任编辑:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值