这版秒杀只是解决瞬间访问过高服务器压力过大,请求速度变慢,大大消耗服务器性能的问题。

主要就是在高并发秒杀的场景下,很多人访问时并没有拿到锁,所以直接跳过了。这样就处理了多线程并发问题的同时也保证了服务器的性能的稳定。

接下来我们使用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分布式锁实现简单秒杀功能的更多相关文章

  1. 单实例redis分布式锁的简单实现

    redis分布式锁的基本功能包括, 同一刻只能有一个人占有锁, 当锁被其他人占用时, 获取者可以等待他人释放锁, 此外锁本身必须能超时自动释放. 直接上java代码, 如下: package com. ...

  2. redis 分布式锁的简单使用

    RedisLock--让 Redis 分布式锁变得简单 目录 1. 项目介绍 2. 快速使用 2.1 引入 maven 坐标 2.2 注册 RedisLock 2.3 使用 3. 参与贡献 4. 联系 ...

  3. 利用redis分布式锁的功能来实现定时器的分布式

    文章来源于我的 iteye blog http://ak478288.iteye.com/blog/1898190 以前为部门内部开发过一个定时器程序,这个定时器很简单,就是配置quartz,来实现定 ...

  4. .NetCore使用Redis,StackExchange.Redis队列,发布与订阅,分布式锁的简单使用

    环境:之前一直是使用serverStack.Redis的客服端,今天来使用一下StackExchange.Redis(个人感觉更加的人性化一些,也是免费的,性能也不会差太多),版本为StackExch ...

  5. Redis分布式锁----乐观锁的实现,以秒杀系统为例

    本文使用redis来实现乐观锁,并以秒杀系统为实例来讲解整个过程. 乐观锁      大多数是基于数据版本(version)的记录机制实现的.即为数据增加一个版本标识,在基于数据库表的版本解决方案中, ...

  6. springboot项目:Redis分布式锁的使用(模拟秒杀系统)

    模拟秒杀系统: 第一步:编写Service package com.payease.service; /** * liuxiaoming * 2017-12-14 */ public interfac ...

  7. 自己写了个简单的redis分布式锁【我】

    自己写了个简单的redis分布式锁 [注意:此锁需要在每次使用前都创建对象,也就是要在线程内每次都创建对象后使用] package redis; import java.util.Collection ...

  8. Redis分布式锁的实现

    前段时间,我在的项目组准备做一个类似美团外卖的拼手气红包[第X个领取的人红包最大],基本功能实现后,就要考虑这一操作在短时间内多个用户争抢同一资源的并发问题了,类似于很多应用如淘宝.京东的秒杀活动场景 ...

  9. Redis分布式锁解决抢购问题

    转:https://segmentfault.com/a/1190000011421467 废话不多说,首先分享一个业务场景-抢购.一个典型的高并发问题,所需的最关键字段就是库存,在高并发的情况下每次 ...

随机推荐

  1. mysql日志详解

    日志分类: 一.错误日志. 1.在配置文件中的配置是:log-error="DESKTOP-igoodful.err",查看参数的键值对:show variables like ' ...

  2. linux常用命令:tr 命令

    tr 命令实现字符转换功能,其功能类似于 sed 命令,但是,tr 命令比 sed 命令简单.也就是说,tr 命令能实现的功能,sed 命令都可以实现.尽管如此,tr 命令依然是 Linux 系统下处 ...

  3. java接口对接——调用别人接口推送数据

    实际开发中经常会遇到要和其他平台或系统对接的情况,实际操作就是互相调用别人的接口获取或者推送数据, 当我们调用别人接口推送数据时,需要对方给一个接口地址以及接口的规范文档,规范中要包括接口的明确入参及 ...

  4. python xml childNodes,childNodes[1].childNodes[0].data例子

    xml: <?xml version='1.0' encoding='utf-8'?><!--this is a test about xml--><booklist t ...

  5. sql的函数和存储过程的区别

    本文部分内容转自http://www.cnblogs.com/lengbingshy/archive/2010/02/25/1673476.html 本质上没区别.只是函数有如:只能返回一个变量的限制 ...

  6. OAuth : open Authorization 开发授权

    OAuth : open Authorization 开发授权 用户访问慕课网,慕课网请求OAuth登陆页面,用户输入QQ号码和密码,这个页面的域名不属于慕课网是属于QQ的,随后把结果给慕课网,这个结 ...

  7. MockWebServer--环境

    MockWebServer是一个可脚本化的用于测试HTTP客户端的Web服务器.主要用于测试你的应用在进行HTTP.HTTPS请求时是否按照预期的行为动作.使用该工具,你可以验证应用的请求是否符合预期 ...

  8. 教你如何在linux下查看服务是否已经启动或者关闭

    1. # ps aux | grep 服务名称(ps 的参数是可以颠倒使用没问题) 2. # netstat -tunple | grep 服务端口 3.bind() 80 in using 代表的含 ...

  9. c++不自动生成相关函数比如赋值、拷贝函数

    默认情况下,如果没有明确声明某些函数比如赋值.拷贝函数,c++会自动生成这些函数,通常他们是对成员进行by-value拷贝,有些时候,赋值.拷贝对象并无什么意义或者不合理,比如对于socket或者th ...

  10. 20145216史婧瑶《网络对抗》逆向及Bof进阶实践

    20145216史婧瑶<网络对抗>逆向及Bof进阶实践 基础知识 Shellcode实际是一段代码,但却作为数据发送给受攻击服务器,将代码存储到对方的堆栈中,并将堆栈的返回地址利用缓冲区溢 ...