利用 Redis 锁解决高并发问题
这里我们主要利用 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 锁解决高并发问题的更多相关文章
- 利用Redis锁解决高并发问题
这里我们主要利用Redis的setnx的命令来处理高并发. setnx 有两个参数.第一个参数表示键.第二个参数表示值.如果当前键不存在,那么会插入当前键,将第二个参数做为值.返回 1.如果当前键存在 ...
- PHP利用Mysql锁解决高并发
前面写过利用文件锁来处理高并发的问题的,现在我们说另外一个处理方式,利用Mysql的锁来解决高并发的问题 先看没有利用事务的时候并发的后果 创建库存管理表 CREATE TABLE `storage` ...
- 高并发场景系列(一) 利用redis实现分布式事务锁,解决高并发环境下减库存
原文:http://blog.csdn.net/heyewu4107/article/details/71009712 高并发场景系列(一) 利用redis实现分布式事务锁,解决高并发环境下减库存 问 ...
- 利用redis实现分布式事务锁,解决高并发环境下库存扣减
利用redis实现分布式事务锁,解决高并发环境下库存扣减 问题描述: 某电商平台,首发一款新品手机,每人限购2台,预计会有10W的并发,在该情况下,如果扣减库存,保证不会超卖 解决方案一 利用数据 ...
- 使用数据库乐观锁解决高并发秒杀问题,以及如何模拟高并发的场景,CyclicBarrier和CountDownLatch类的用法
数据库:mysql 数据库的乐观锁:一般通过数据表加version来实现,相对于悲观锁的话,更能省数据库性能,废话不多说,直接看代码 第一步: 建立数据库表: CREATE TABLE `skill_ ...
- Redis+Lua解决高并发场景抢购秒杀问题
之前写了一篇PHP+Redis链表解决高并发下商品超卖问题,今天介绍一些如何使用PHP+Redis+Lua解决高并发下商品超卖问题. 为何要使用Lua脚本解决商品超卖的问题呢? Redis在2.6版本 ...
- php解决高并发问题
我们通常衡量一个Web系统的吞吐率的指标是QPS(Query Per Second,每秒处理请求数),解决每秒数万次的高并发场景,这个指标非常关键.举个例子,我们假设处理一个业务请求平均响应时间为10 ...
- 转发:php解决高并发
php解决高并发(转发:https://www.cnblogs.com/walblog/articles/8476579.html) 我们通常衡量一个Web系统的吞吐率的指标是QPS(Query Pe ...
- asp.net解决高并发的方案.
asp.net解决高并发的方案. Posted on 2012-11-27 22:31 75077027 阅读(3964) 评论(1) 编辑 收藏 最近几天一直在读代震军的博客,他是 Discuz!N ...
随机推荐
- 在Mac电脑上使用NTFS移动硬盘遇到问题
1.sudo nano/etc/fstab 回车 输电脑密码 2.进入文本插入页面 编入: LABEL=硬盘名字 NONE ntfs rw,auto,nobrowse 3.ctrl + X 退出 选 ...
- POJ 2502 Subway ( 最短路 && 最短路建图 )
题意 : 给出二维平面上的两个点代表起点以及终点,接下来给出若干条地铁线路,除了在地铁线路上行进的速度为 40km/h 其余的点到点间都只能用过步行且其速度为 10km/h ,现问你从起点到终点的最短 ...
- sqlserver库相关-表相关-3
原文: https://www.cnblogs.com/wlx520/p/4684441.html 库相关 建库 --创建School数据库之前:首先判断数据库是否存在,若存在则删除后再创建,若不存在 ...
- 在getview方法中有三个参数,起到优化的部分为ViewHolder的使用,主要方法setTag(),getTag()
适配器代码如下: public class Myadapter extends BaseAdapter { List<String> date; Context context; //构造 ...
- ajax跨域处理 No 'Access-Control-Allow-Origin' header is present on the requested resource 问题
Controller层的类上增加@CrossOrign注解,当前文件的所有接口就都可以被调用 spring注解@CrossOrigin不起作用的原因 1.是springMVC的版本要在4.2或以上版本 ...
- python安装centos7
1.安装git (需root权限) yum -y install git 2.安装依赖包 yum -y install gcc make patch gdbm-devel openssl-devel ...
- golang简介
GO语言是Google于2009年推出的一门新的系统编程语言 特点: 静态编译 垃圾回收 简洁的符号和语法 平坦的类型系统 基于CSP的并发模型 高效简单的工具链 丰富的标准库 为什么选择go语言 编 ...
- 【题解】Sigitseeing Tour
题目大意 有一张$n$个结点,$m$条混合边的图($1 \leq n \leq 200$,$1 \leq m \leq 1000$),求这张图是否存在欧拉回路. 题解 因为有混合边,所以我们要先给无向 ...
- POJ 3764 The xor-longest Path (01字典树)
<题目链接> 题目大意: 给定一颗$n$个节点$(n\leq10^5)$,有边权的树,其边权$(0\leq w < 2^{31})$.让你求出这棵树上任意两个节点之间的异或最大值. ...
- MyBatis 配置/注解 SQL CRUD 经典解决方案(2019.08.15持续更新)
本文旨在记录使用各位大神的经典解决方案. 2019.08.14 更新 Mybatis saveOrUpdate SelectKey非主键的使用 MyBatis实现SaveOrUpdate mybati ...