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

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); } return false; } }

/** * @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 锁是可以有效的处理高并发的。

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

出处:http://u6.gg/s2mCt

利用 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. php stripos()函数 语法

    php stripos()函数 语法 作用:寻找字符串中某字符最先出现的位置,不区分大小写.直线电参数 语法:stripos(string,find,start) 参数: 参数 描述 string  ...

  2. 顺序表 C++ 类模板实现

    顺序表的C++语言描述 基本运算的算法——置空表.求表的长度.取结点.定位运算.插入运算.删除运算.建立顺序表.输出顺序表 #include <iostream>using namespa ...

  3. ORACLE错误:ORA-28001: the password has expired解决方法

    Oracle提示错误消息ORA-28001: the password has expired,是由于Oracle11G的新特性所致, Oracle11G创建用户时缺省密码过期限制是180天(即6个月 ...

  4. sscanf sscanf_s使用

    #include<stdio.h> 定义函数 int sscanf (const char *str,const char * format,........); 函数说明  sscanf ...

  5. poj1163The Triangle(动态规划,记忆化搜索)

    7 3 8 8 1 0 2 7 4 4 4 5 2 6 5 (Figure 1) Figure 1 shows a number triangle. Write a program that calc ...

  6. 网络流强化-HDU 3338-上下界限制最大流

    题意是: 一种特殊的数独游戏,白色的方格给我们填1-9的数,有些带数字的黑色方格,右上角的数字代表从他开始往右一直到边界或者另外一个黑格子,中间经过的白格子的数字之和要等于这个数字:左下角的也是一样的 ...

  7. 12.定义Lock类,用于锁定数据.三步走,锁的优缺点

    #在threading模块当中定义了一个Lock类,可以方便的使用锁定: # #1.创建锁 # mutex = threading.Lock() # # #2.锁定 ''' mutex.acquire ...

  8. jQuery基础--jQuery特殊属性操作

    1.index() 会返回当前元素在所有兄弟元素里面的索引. <!DOCTYPE html> <html lang="zh-CN"> <head> ...

  9. python参数的介绍

    一.函数1.为什么要使用函数?减少代码的冗余2.函数先定义后使用(相当于变量一样先定义后使用)3.函数的分类:内置函数:python解释器自带的,直接拿来用就行了自定义函数:根据自己的需求自己定义的函 ...

  10. javaScript Map

                  }                   } }                          vertices.push(v);         adjList.set ...