Redis分布式锁实现简单秒杀功能
这版秒杀只是解决瞬间访问过高服务器压力过大,请求速度变慢,大大消耗服务器性能的问题。
主要就是在高并发秒杀的场景下,很多人访问时并没有拿到锁,所以直接跳过了。这样就处理了多线程并发问题的同时也保证了服务器的性能的稳定。
接下来我们使用redis的分布式锁来进行枷锁处理:
我们可以在进入下单的方法后将核心的方法加锁,然后离开后进行解锁
主要三步:
加锁
核心方法
解锁
首页分布式加锁解锁工具类:
@Component
public class RedisLock {
private static Logger logger = LoggerFactory.getLogger(RedisLock.class); @Autowired
private StringRedisTemplate redisTemplate; /**
* 加锁
* @param key
* @param value 当前事件+超时事件
* @return
*/
public boolean lock(String key,String value){
//加锁成功
if (redisTemplate.opsForValue().setIfAbsent(key,value)){
return true;
}
//假如currentValue=A先占用了锁 其他两个线程的value都是B,保证其中一个线程拿到锁
String currentValue = redisTemplate.opsForValue().get(key);
//锁过期 防止出现死锁
if (!StringUtils.isEmpty(currentValue) &&
Long.parseLong(currentValue) < System.currentTimeMillis()){
//获取上一步锁的时间
String oldValue = redisTemplate.opsForValue().getAndSet(key, value);
if (!StringUtils.isEmpty(oldValue) &&
oldValue.equals(currentValue)){
return true;
}
}
return false;
} /**
* 解锁
* @param key
* @param value
*/
public void unlock(String key,String value){
try {
String currentValue = redisTemplate.opsForValue().get(key);
if (!StringUtils.isEmpty(currentValue) &&
currentValue.equals(value)){
redisTemplate.opsForValue().getOperations().delete(key);
}
}catch (Exception e){
logger.error("【redis分布式锁】 解锁异常,{}",e);
}
}
}
具体使用的逻辑代码功能:
@Service
public class SecKillService {
private static Logger logger = LoggerFactory.getLogger(SecKillService.class);
/** 超时时间 */
private static final int TIMEOUT = 10000; @Autowired
private RedisLock redisLock;
@Autowired
private RedisClient redisClient;
@Autowired
private RestTemplate restTemplate; /**
* @Description: 秒杀商品接口
* @param weddingExpoAppoint
* @return JsonObject
* @exception
* @author mazhq
* @date 2018/11/18 13:46
*/
private JsonObject seckillProduct(long productId) {
long time = System.currentTimeMillis() + TIMEOUT;
String stockKey = RedisKeysManager.getWeddingExpoSeckillStockKey(productId);
//加锁
String lockKey = "weddingExpo:seckill:"+productId;
if (!redisLock.lock(lockKey,String.valueOf(time))){
return BaseCode.retCode(100, "没抢到,换个姿势再来一遍");
} String stockNumStr = redisClient.getStr(stockKey);
int stockNum = 0;
if(StringUtils.isNotBlank(stockNumStr)){
stockNum = Integer.valueOf(stockNumStr);
}
JsonObject respJson = BaseCode.retCode(ResultCode.failure);
if (stockNum == 0) {
//库存不足
return BaseCode.retCode(100, "商品已经被抢光了,请留意下次活动");
} else { try {
String resp = doseckill(productId);
if(null != resp){
respJson = new JsonObject(resp);
if(respJson.getInteger("retcode") == 0){
redisClient.increment(stockKey, -1);
}
Thread.sleep(100);
}
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
//解锁
redisLock.unlock(lockKey, String.valueOf(time));
return respJson;
} }
主要功能描述就是:
秒杀商品时候先加锁,如果没有获取到锁就释放请求。
加锁后先进行库存判断如果不足释放请求。
进行秒杀下单流程,如果成功库存做减一操作。
最后释放分布式锁。
这样简单的分布式锁处理秒杀功能的方法就搞定了。这种只是处理高并发下多个请求如果有人在秒杀后面的直接不需排队直接释放请求,解放服务器压力(处理流程时间较短,高并发下没有排序要求)。
如果要根据请求时间进行排序,这个方式还需借助队列处理。
Redis分布式锁实现简单秒杀功能的更多相关文章
- 单实例redis分布式锁的简单实现
redis分布式锁的基本功能包括, 同一刻只能有一个人占有锁, 当锁被其他人占用时, 获取者可以等待他人释放锁, 此外锁本身必须能超时自动释放. 直接上java代码, 如下: package com. ...
- redis 分布式锁的简单使用
RedisLock--让 Redis 分布式锁变得简单 目录 1. 项目介绍 2. 快速使用 2.1 引入 maven 坐标 2.2 注册 RedisLock 2.3 使用 3. 参与贡献 4. 联系 ...
- 利用redis分布式锁的功能来实现定时器的分布式
文章来源于我的 iteye blog http://ak478288.iteye.com/blog/1898190 以前为部门内部开发过一个定时器程序,这个定时器很简单,就是配置quartz,来实现定 ...
- .NetCore使用Redis,StackExchange.Redis队列,发布与订阅,分布式锁的简单使用
环境:之前一直是使用serverStack.Redis的客服端,今天来使用一下StackExchange.Redis(个人感觉更加的人性化一些,也是免费的,性能也不会差太多),版本为StackExch ...
- Redis分布式锁----乐观锁的实现,以秒杀系统为例
本文使用redis来实现乐观锁,并以秒杀系统为实例来讲解整个过程. 乐观锁 大多数是基于数据版本(version)的记录机制实现的.即为数据增加一个版本标识,在基于数据库表的版本解决方案中, ...
- springboot项目:Redis分布式锁的使用(模拟秒杀系统)
模拟秒杀系统: 第一步:编写Service package com.payease.service; /** * liuxiaoming * 2017-12-14 */ public interfac ...
- 自己写了个简单的redis分布式锁【我】
自己写了个简单的redis分布式锁 [注意:此锁需要在每次使用前都创建对象,也就是要在线程内每次都创建对象后使用] package redis; import java.util.Collection ...
- Redis分布式锁的实现
前段时间,我在的项目组准备做一个类似美团外卖的拼手气红包[第X个领取的人红包最大],基本功能实现后,就要考虑这一操作在短时间内多个用户争抢同一资源的并发问题了,类似于很多应用如淘宝.京东的秒杀活动场景 ...
- Redis分布式锁解决抢购问题
转:https://segmentfault.com/a/1190000011421467 废话不多说,首先分享一个业务场景-抢购.一个典型的高并发问题,所需的最关键字段就是库存,在高并发的情况下每次 ...
随机推荐
- ExtJs中XTemplate使用(转)
转自http://www.studyofnet.com/news/408.html 本文导读:XTemplate是Ext.Template扩展的新类,它支持高级功能的模板类,如自动数组输出.条件判断. ...
- UBUNTU16.04 使用APT-GET如何设置代理
sudo apt-get install software-name -o Acquire::http::proxy="http://用户名:密码@代理服务器IP:代理服务器端口&quo ...
- QQ 客服设置
不说那么多了. 目前可以通过此方式实现添加的效果 <a target="_blank" href="http://wpa.qq.com/msgrd?v=3& ...
- C# 将字节流转换为图片的实例方法(转)
代码如下: usingSystem; usingSystem.Collections.Generic; usingSystem.Linq; usingSystem.Text; usingSystem. ...
- HTML ajax 上传文件限制文件的类型和文件大小
html <input type="file" name="excel" id="excel_input" accept=&qu ...
- 50道JavaScript基础面试题(附答案)
https://segmentfault.com/a/1190000015288700 1 介绍JavaScript的基本数据类型 Number.String .Boolean .Null.Undef ...
- Linux Touch命令的8种使用技巧
Linux touch命令不仅可以用于在Linux上创建空文件. 您可以使用它来更改现有文件的时间戳,包括其访问权限和修改时间. 本文介绍了8种可以通过Linux终端使用touch命令的方案. 我们在 ...
- 计算概论(A)/基础编程练习1(8题)/5:鸡兔同笼
#include<stdio.h> int main() { // 鸡兔同笼中脚的总数:a < 32768 int a; scanf("%d", &a); ...
- ubuntu 安转redis
一 ,redis 安装配置 在 Ubuntu 系统安装 Redis 可以使用以下命令: sudo apt-get update sudo apt-get install redis-server 这样 ...
- HDU 1863 畅通工程 (最小生成树
看卿学姐视频学到的题目 kruskal算法实现最小生成树 #include<bits/stdc++.h> using namespace std; ; typedef long long ...