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

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

创建库存表


CREATE TABLE `storage` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`number` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1

设置初始库存为10

创建订单表


CREATE TABLE `order` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`number` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1

测试不用锁的时候


$pdo = new PDO('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 |
+----+--------+
1 row in set (0.00 sec)

在来看订单表


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 in set (0.00 sec)

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

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


<?php
/**
* Created by PhpStorm.
* User: daisc
* Date: 2018/7/23
* Time: 14:45
*/
class Lock
{
private static $_instance ;
private $_redis;
private function __construct()
{
$this->_redis = new Redis();
$this->_redis ->connect('127.0.0.1');
}
public static function getInstance()
{
if(self::$_instance instanceof self)
{
return self::$_instance;
}
return self::$_instance = new self();
} /**
* @function 加锁
* @param $key 锁名称
* @param $expTime 过期时间
*/
public function set($key,$expTime)
{
//初步加锁
$isLock = $this->_redis->setnx($key,time()+$expTime);
if($isLock)
{
return true;
}
else
{
//加锁失败的情况下。判断锁是否已经存在,如果锁存在切已经过期,那么删除锁。进行重新加锁
$val = $this->_redis->get($key);
if($val&&$val<time())
{
$this->del($key);
}
return $this->_redis->setnx($key,time()+$expTime);
}
} /**
* @param $key 解锁
*/
public function del($key)
{
$this->_redis->del($key);
} } $pdo = new PDO('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 in set (0.00 sec)

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

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

原文地址:https://segmentfault.com/a/1190000016251978

利用Redis锁解决高并发问题的更多相关文章

  1. 利用 Redis 锁解决高并发问题

    这里我们主要利用 Redis 的 setnx 的命令来处理高并发. setnx 有两个参数.第一个参数表示键.第二个参数表示值.如果当前键不存在,那么会插入当前键,将第二个参数做为值.返回 1.如果当 ...

  2. PHP利用Mysql锁解决高并发

    前面写过利用文件锁来处理高并发的问题的,现在我们说另外一个处理方式,利用Mysql的锁来解决高并发的问题 先看没有利用事务的时候并发的后果 创建库存管理表 CREATE TABLE `storage` ...

  3. 高并发场景系列(一) 利用redis实现分布式事务锁,解决高并发环境下减库存

    原文:http://blog.csdn.net/heyewu4107/article/details/71009712 高并发场景系列(一) 利用redis实现分布式事务锁,解决高并发环境下减库存 问 ...

  4. 利用redis实现分布式事务锁,解决高并发环境下库存扣减

    利用redis实现分布式事务锁,解决高并发环境下库存扣减   问题描述: 某电商平台,首发一款新品手机,每人限购2台,预计会有10W的并发,在该情况下,如果扣减库存,保证不会超卖 解决方案一 利用数据 ...

  5. 使用数据库乐观锁解决高并发秒杀问题,以及如何模拟高并发的场景,CyclicBarrier和CountDownLatch类的用法

    数据库:mysql 数据库的乐观锁:一般通过数据表加version来实现,相对于悲观锁的话,更能省数据库性能,废话不多说,直接看代码 第一步: 建立数据库表: CREATE TABLE `skill_ ...

  6. Redis+Lua解决高并发场景抢购秒杀问题

    之前写了一篇PHP+Redis链表解决高并发下商品超卖问题,今天介绍一些如何使用PHP+Redis+Lua解决高并发下商品超卖问题. 为何要使用Lua脚本解决商品超卖的问题呢? Redis在2.6版本 ...

  7. php解决高并发问题

    我们通常衡量一个Web系统的吞吐率的指标是QPS(Query Per Second,每秒处理请求数),解决每秒数万次的高并发场景,这个指标非常关键.举个例子,我们假设处理一个业务请求平均响应时间为10 ...

  8. 转发:php解决高并发

    php解决高并发(转发:https://www.cnblogs.com/walblog/articles/8476579.html) 我们通常衡量一个Web系统的吞吐率的指标是QPS(Query Pe ...

  9. asp.net解决高并发的方案.

    asp.net解决高并发的方案. Posted on 2012-11-27 22:31 75077027 阅读(3964) 评论(1) 编辑 收藏 最近几天一直在读代震军的博客,他是 Discuz!N ...

随机推荐

  1. 【翻译自mos文章】在12c数据库中,哪种audit trail 受到支持?

    在12c数据库中,哪种audit trail 受到支持? 来源于:What Audit Trail Types Are Supported For A 12c Database? (文档 ID 198 ...

  2. win7_32虚拟机网络设置

    今天工作中同事需要使用ie8的浏览器,组内同事没有,想到自己玩的win7_32虚拟机上有ie8,想让对方连接使用,发现自己本机可以远程连接,同事不能连接 排查原因:可能虚拟机使用的是nat模式连接的网 ...

  3. 初探Java中的异常处理

      Java中的异常有以下几种: 1) Error:Java运行时的内部错误. 2) Exception:程序中应该捕获的异常.          RuntimeException:因为编程产生的错误 ...

  4. Hadoop - MapReduce MRAppMaster-剖析

      一 概述         MRv1主要由编程模型(MapReduce API).资源管理与作业控制块(由JobTracker和TaskTracker组成)和数据处理引擎(由MapTask和Redu ...

  5. Java8新特性之Optional

    空指针异常一直是困扰Java程序员的问题,也是我们必须要考虑的.当业务代码中充满了if else判断null 的时候程序变得不再优雅,在Java8中提供了Optional类为我们解决NullPoint ...

  6. iOS版本、iPhone版本、Xcode版本比对

    iOS版本 iPhone版本 Xcode版本 其他 2003年 Xcode1.0 2005年4月29日 Xcode2.0 2007年1月9日 iPhone OS(iOS1): 虚拟键盘.谷歌地图 第一 ...

  7. Docker 常用命令和命令集结

    常用命令 查看版本 docker version 查看系统信息 docker info 显示 Docker 系统信息,包括镜像和容器数. 搜索镜像 docker search keyword 从 Do ...

  8. golang——(strings包)常用字符串操作函数

    (1)func HasPrefix(s, prefix string) bool 判断字符串s是否有前缀字符串prefix: (2)func HasSuffix(s, suffix string) b ...

  9. POJ 2976 裸的01分数规划

    题意:给你n个数对(认为是a数组和b数组吧),从中取n-m个数对,如果选第i个数对,定义x[i]=1,求R=∑(a[i]*x[i])/∑(b[i]*x[i])取得最大值时R的值.输出R*100(保留到 ...

  10. .net中的WebForm引人MVC的控制器

    当下.net中比较火的模式MVC模式,说实话对于菜鸟的我还没有遇到一个比较健全的MVC模式的项目也是比较遗憾.偶然间在网上看到WebForm实现MVC中的模式(主要是控制器...)就学习了一波,下面是 ...