模拟秒杀系统:

第一步:编写Service

package com.payease.service;

/**
* liuxiaoming
* 2017-12-14
*/
public interface SecKillService {
/**
* 查询秒杀活动特价商品的信息
*
* @param productId
* @return
*/
String querySecKillProductInfo(String productId); /**
* 模拟不同用户秒杀同一商品的请求
*
* @param productId
* @return
*/
void orderProductMockDiffUser(String productId);
}

第二步:编写Redis加锁解锁工具类

package com.payease.service;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils; /**
* liuxiaoming
* 2017-12-14
*/
@Component
@Slf4j
public class RedisLock { @Autowired
private StringRedisTemplate stringRedisTemplate; /**
* 加锁
* @param key
* @param value 当前时间+超时时间
* @return
*/
public boolean lock(String key, String value) {
if (stringRedisTemplate.opsForValue().setIfAbsent(key, value)) {
return true;
}
//currentValue=A 这两个线程的value都是B 其中一个线程拿到锁
String currentValue = stringRedisTemplate.opsForValue().get(key);
//如果锁过期
if (!StringUtils.isEmpty(currentValue) && Long.parseLong(currentValue) < System.currentTimeMillis()) {
//获取上一个锁的时间
String oldValue = stringRedisTemplate.opsForValue().getAndSet(key, value);
if (!StringUtils.isEmpty(oldValue) && oldValue.equals(currentValue)) {
return true;
}
}
return false;
} /**
* 解锁
* @param key
* @param value
* @return
*/
public void unlock(String key, String value) {
String currentVaule = stringRedisTemplate.opsForValue().get(key);
try {
if (!StringUtils.isEmpty(currentVaule) && currentVaule.equals(value)) {
stringRedisTemplate.opsForValue().getOperations().delete(key);
}
} catch (Exception e) {
log.error("【redis分布式锁】解锁异常,{}" , e);
} }
}

第三步:编写Service实现类

package com.payease.service.impl;

import com.payease.exception.SellException;
import com.payease.service.RedisLock;
import com.payease.service.SecKillService;
import com.payease.utils.KeyUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import java.util.HashMap;
import java.util.Map; /**
* liuxiaoming
* 1027-12-14
*/
@Service
public class SecKillServiceImpl implements SecKillService { @Autowired
private RedisLock redisLock; private static final int TIMOUT = 10 * 1000; //超时时间 10秒 /**
* 中秋活动 秒杀月饼 限量100000
*/
static Map<String, Integer> products;
static Map<String, Integer> stock;
static Map<String, String> orders; static {
products = new HashMap<>();
stock = new HashMap<>();
orders = new HashMap<>();
products.put("abc123456", 10000);
stock.put("abc123456", 10000);
} private String queryMap(String productId) {
return "中秋活动,月饼特价,限量份"
+ products.get(productId)
+ " 还剩:" + stock.get(productId) + " 份"
+ " 该商品成功下单用户数目:"
+ orders.size() + " 人";
} @Override
public String querySecKillProductInfo(String productId) {
return queryMap(productId);
} /**
* 描述逻辑
*
* @param productId
*/
@Override
public void orderProductMockDiffUser(String productId) { //加锁
long time = System.currentTimeMillis() + TIMOUT;
if (!redisLock.lock(productId, String.valueOf(time))) {
throw new SellException(110, "没抢到,换个姿势再试一遍呀");
}
//1. 查询该商品库存,为0则活动结束。
int stockNum = stock.get(productId);
if (stockNum == 0) {
//库存不足
throw new SellException(100, "活动已经结束,请留意下次活动");
} else { orders.put(KeyUtil.getUniqueKey(), productId);
stockNum = stockNum - 1;
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
stock.put(productId, stockNum);
} //解锁
redisLock.unlock(productId, String.valueOf(time));
} /*@Override
public synchronized void orderProductMockDiffUser(String productId) {
int stockNum = stock.get(productId);
if (stockNum == 0) {
//库存不足
throw new SellException(100, "活动已经结束,请留意下次活动");
} else { orders.put(KeyUtil.genUniqueKey(), productId);
stockNum = stockNum - 1;
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
stock.put(productId, stockNum);
} }*/
}

第四步:编写controller

package com.payease.controller;

import com.payease.service.SecKillService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; @RestController
@RequestMapping("/skill")
@Slf4j
public class SecKillController { @Autowired
private SecKillService secKillService; /**
* 查询秒杀活动特价商品的信息
* @param productId
* @return
*/
@GetMapping("/query/{productId}")
public String query(@PathVariable String productId)throws Exception
{
return secKillService.querySecKillProductInfo(productId);
} /**
* 秒杀,没有抢到获得"哎呦喂,xxxxx",抢到了会返回剩余的库存量
* @param productId
* @return
* @throws Exception
*/
@GetMapping("/order/{productId}")
public String skill(@PathVariable String productId)throws Exception
{
log.info("@skill request, productId:" + productId);
secKillService.orderProductMockDiffUser(productId);
return secKillService.querySecKillProductInfo(productId);
}
}

第五步:启动项目 查看浏览器 进行压测

1.查看秒杀情况 http://127.0.0.1:8080/sell/skill/query/abc123456

2. 在Mac终端输入命令: ab -n 500 -c 100 http://127.0.0.1:8080/sell/skill/order/abc123456
进行压测

3.查看浏览器 http://127.0.0.1:8080/sell/skill/query/abc123456

注:

压测模拟并发:

springboot项目:Redis分布式锁的使用(模拟秒杀系统)的更多相关文章

  1. SpringBoot集成Redis分布式锁以及Redis缓存

    https://blog.csdn.net/qq_26525215/article/details/79182687 集成Redis 首先在pom.xml中加入需要的redis依赖和缓存依赖 < ...

  2. springBoot实现redis分布式锁

    参考:https://blog.csdn.net/weixin_44634197/article/details/108308395 .. 使用redis的set命令带NX(not exist)参数实 ...

  3. springboot+redis分布式锁-模拟抢单

    本篇内容主要讲解的是redis分布式锁,这个在各大厂面试几乎都是必备的,下面结合模拟抢单的场景来使用她:本篇不涉及到的redis环境搭建,快速搭建个人测试环境,这里建议使用docker:本篇内容节点如 ...

  4. 用压测模拟并发、并发处理(synchronized,redis分布式锁)

    使用工具:Apache an 测压命令: ab -n 100 -c 100 http://www.baidu.com -n代表模拟100个请求,-c代表模拟100个并发,相当于100个人同时访问 ab ...

  5. spring-boot 中实现标准 redis 分布式锁

    一,前言 redis 现在已经成为系统缓存的必备组件,针对缓存读取更新操作,通常我们希望当缓存过期之后能够只有一个请求去更新缓存,其它请求依然使用旧的数据.这就需要用到锁,因为应用服务多数以集群方式部 ...

  6. redis分布式锁在springboot中的实现

    理论知识   redis分布式锁的实现方案请参考文章 如何优雅地用redis实现分布式锁 本案例简介   以秒杀活动为例子,在多线程高并发的情况下需要保证秒杀业务的线程安全性,确保秒杀记录与所扣库存数 ...

  7. 项目中用到了Redis分布式锁,了解一下背后的原理

    前言 以前在学校做小项目的时候,用到Redis,基本也只是用来当作缓存.现在博主在某金融平台实习,发现Redis在生产中并不只是当作缓存这么简单.在我接触到的项目中,Redis起到了一个分布式锁的作用 ...

  8. 基于SpringBoot AOP面向切面编程实现Redis分布式锁

    基于SpringBoot AOP面向切面编程实现Redis分布式锁 基于SpringBoot AOP面向切面编程实现Redis分布式锁 基于SpringBoot AOP面向切面编程实现Redis分布式 ...

  9. Redis分布式锁升级版RedLock及SpringBoot实现

    分布式锁概览 在多线程的环境下,为了保证一个代码块在同一时间只能由一个线程访问,Java中我们一般可以使用synchronized语法和ReetrantLock去保证,这实际上是本地锁的方式.但是现在 ...

随机推荐

  1. Hadoop中Writable类之二

    1.ASCII.Unicode.UFT-8 在看Text类型的时候,里面出现了上面三种编码,先看看这三种编码: ASCII是基于拉丁字母的一套电脑编码系统.它主要用于显示现代英语和其他西欧语言.它是现 ...

  2. 移动lob类型索引到指定表空间

    WWWNEWSAD 为表名 USERS 为原表空间 CONTENT 为lob类型的字段 DATA_INDEX_WXZJ 指定的表空间 ALTER TABLE WWWNEWSAD MOVE TABLES ...

  3. 一款好用的js插件及工具包

    笔记:需要源码私信 script文件夹 script下的目录文件: 使用的效果,解决ie兼容性问题,好处多多!慢慢参考! 具体用法: 前端引入js,写必须要的js脚本! <script src= ...

  4. type="submit" 和type="button"

    今天,小菜鸟又遇到一个问题,当不小心在页面输入框回车一下,结果莫名的页面发出了一个请求. 把问题定位在一个button上,代码是这样写的<button class="btn btn-d ...

  5. CentOS 6.0下phpvod搭建教程(LAMP+phpvod)

    之所以安装CentOS是因为之前试过RedHat,但是发现RedHat在安装时,无法获取安装源,原因是RedHat系统没有在RHN注册. 网上的很多教程都说可以直接换用CentOS的源,可我小搞里一会 ...

  6. Android-图像原理/绘制原理

    图像原理 先专门讲解图片,一想到图片有那些特点:    宽/高 格式jpg/jpeg/... 大小43.kb/... 图片是由像素点组成:像素点是正方形的,只是像素点很小很多,看起来可以拼接圆形⭕️, ...

  7. css 颜色渐变 兼容性

    参考文献:http://caibaojian.com/css3-background-gradient.html    https://www.cnblogs.com/xzzzys/p/7495725 ...

  8. django:multivaluedictkeyerror错误

    查了一下,是因为获取前台数据时,用了request.POST[],改用request.POST.get()之后没有这个报错了 细节: request.POST是用来接受从前端表单中传过来的数据,比如用 ...

  9. C# Session操作

    Session.Abandon();//清除全部Session//清除某个SessionSession["UserName"] = null;Session.Remove(&quo ...

  10. C# AutoMapper的简单扩展

    AutoMapper可以很方便的将一个实体的属性值转化给另一个对象.这个功能在我们日常的编码中经常会遇到.我将AutoMapper的一些基本映射功能做成扩展方法,在编码中更方便使用. using Sy ...