文章目录所谓秒杀,从业务角度看,是短时间内多个用户“争抢”资源,这里的资源在大部分秒杀场景里是商品;将业务抽象,技术角度看,秒杀就是多个线程对资源进行操作,所以实现秒杀,就必须控制线程对资源的争抢,既要保证高效并发,也要保证操作的正确。
- SpringBoot +Redis +RabbitMQ 实现高并发限时秒杀
- 开发环境
- 测试环境
- 环境安装
- 安装RabbitMQ
- 安装Redis
- 安装 Jmeter测试工具
- maven安装
- 代码模块
- 数据库设计
- 商品库存表:stock
- 秒杀订单表:t_order
- pom.xml
- application.yml
- logback-spring.xml
- 实体类
- 服务层
- 接口实现类
- 配置rabbitmq的实现方式以及redis的实现方式
- 工具类
- 控制层
- 启动项目
- 启动完成,redis中上架10个货物。
- 打开JMeter并发环境测试
- log日志
SpringBoot+mysql+maven+JDK8+RabbitMQ+Redis
测试环境Jmeter测试工具
环境安装 安装RabbitMQdocker安装:https://blog.csdn.net/qq_33612228/article/details/103732890
windows安装:https://blog.csdn.net/m0_37034294/article/details/82839494
需要安装mq的可视化工具
docker安装:https://blog.csdn.net/qq_33612228/article/details/10360918
windows安装:https://blog.csdn.net/qq_39135287/article/details/82686837
springboot整合redis:https://blog.csdn.net/qq_33612228/article/details/103700543
redis需要安装客户端,方便数据查看。
windows安装:https://blog.csdn.net/liuyanh2006/article/details/82494548
mac安装: https://blog.csdn.net/zgy_boke/article/details/102689531
mac安装需要的Homebrew:https://blog.csdn.net/o_o814222198/article/details/120185851?spm=1001.2014.3001.5502
mac安装:https://www.jianshu.com/p/191685a33786
window安装:https://www.cnblogs.com/eagle6688/p/7838224.html
CREATE TABLE `stock` ( `id` varchar(64) NOT NULL, `name` varchar(255) DEFAULT NULL, `stock` varchar(255) DEFAULT NULL, `remarks` varchar(255) NOT NULL DEFAULT '' COMMENT '备注', `update_date` datetime DEFAULT NULL COMMENT '最后更新时间', `create_date` datetime DEFAULT NULL COMMENT '创建时间', `update_by` varchar(64) NOT NULL DEFAULT '', `create_by` varchar(64) NOT NULL DEFAULT '', `del_flag` char(1) NOT NULL DEFAULT '0' COMMENT '0正常,1删除', PRIMARY KEY (`id`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 ROW_FORMAT=DYNAMIC COMMENT='商品库存表';秒杀订单表:t_order
CREATE TABLE `t_order` ( `id` varchar(64) NOT NULL, `order_name` varchar(255) DEFAULT NULL, `order_user` varchar(255) DEFAULT NULL, `remarks` varchar(255) NOT NULL DEFAULT '' COMMENT '备注', `update_date` datetime DEFAULT NULL COMMENT '最后更新时间', `create_date` datetime DEFAULT NULL COMMENT '创建时间', `update_by` varchar(64) NOT NULL DEFAULT '', `create_by` varchar(64) NOT NULL DEFAULT '', `del_flag` char(1) NOT NULL DEFAULT '0' COMMENT '0正常,1删除', PRIMARY KEY (`id`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 ROW_FORMAT=DYNAMIC COMMENT='秒杀订单表';pom.xml
- 集成MybatisPlus
- fastjosn依赖
- Druid
- MyBatis增强工具
- lombok
- websocket
- 前端页面通过thymeleaf渲染
- 工具类包
- swagger-ui
- redis
- RabbitMQ
application.yml4.0.0 org.springframework.boot spring-boot-starter-parent 2.1.8.RELEASE com.example demo 0.0.1-SNAPSHOT demo 集成MybatisPlus UTF-8 UTF-8 1.8 1.1.14 8.0.11 3.1.1 3.1.1 1.18.0 2.9.2 1.2.47 1.6 org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-dependencies 2.1.8.RELEASE pom import mysql mysql-connector-java ${mysql-connector-java.version} com.alibaba fastjson ${fastjson.version} com.alibaba druid-spring-boot-starter ${druid.version} com.baomidou mybatis-plus-boot-starter ${mybatis-plus-boot-starter.version} com.baomidou mybatis-plus-generator ${mybatis-plus-generator.version} org.projectlombok lombok ${lombok.version} org.springframework.boot spring-boot-starter-websocket org.springframework.boot spring-boot-starter-thymeleaf org.apache.commons commons-text ${commons-text.version} io.springfox springfox-swagger2 ${swagger.version} io.springfox springfox-swagger-ui ${swagger.version} org.springframework.boot spring-boot-starter-data-redis org.springframework.boot spring-boot-starter-amqp org.springframework.boot spring-boot-starter-test test org.junit.vintage junit-vintage-engine org.springframework.boot spring-boot-maven-plugin
- 数据源
- 端口号
- redis
- mq
- 扫描mapper文件
- 文件上传
- 页面模板
- log日志配置
spring:
datasource:
url: jdbc:mysql://182.92.210.212:3306/order_db?autoReconnect=true&useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false
username: root
password: ***
# 使用Druid数据源
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
druid:
filters: stat
maxActive: 20
initialSize: 1
maxWait: 60000
minIdle: 1
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: select 'x'
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxOpenPreparedStatements: 20
data:
redis:
repositories:
enabled: false
redis:
database: 0 # redis数据库索引(默认为0),我们使用索引为其他(0-15)的数据库,避免和其他数据库冲突
host: 182.92.210.212
port: 6379
password: ***
rabbitmq: #mq配置
host: localhost
port: 5672
username: guest
password: guest
resources:
static-locations: classpath:/static #这个配置项告诉springboot去哪找资源 最关键的地方
profiles:
active: dev
servlet:
multipart:
enabled: true
max-file-size: 10MB #允许上传的文件大小
max-request-size: 10MB
thymeleaf:
cache: false
prefix: classpath:/templates/
suffix: .html
encoding: UTF-8
mode: HTML5
context-type: text/html
mvc:
view:
prefix: /
suffix: .html
static-path-pattern:
@TableName("t_order")
@Data
public class Order extends basePlusEntity{
private static final long serialVersionUID = 1L;
@TableField("order_name")
private String orderName;
@TableField("order_user")
private String orderUser;
}
package com.example.demo.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
@TableName("stock")
@Data
public class Stock extends basePlusEntity{
private static final long serialVersionUID = 1L;
@TableField("name")
private String name;
@TableField("stock")
private String stock;
}
服务层
package com.example.demo.service; import com.baomidou.mybatisplus.extension.service.IService; import com.example.demo.entity.Order; public interface OrderService extends IService{ void saveOrder(Order order); }
package com.example.demo.service; import com.baomidou.mybatisplus.extension.service.IService; import com.example.demo.entity.Stock; public interface StockService extends IService接口实现类{ void decrByStock(String name); Integer selectByName(String name); String secDatabase(String userName,String stockName); }
package com.example.demo.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.example.demo.entity.Order; import com.example.demo.exception.SXException; import com.example.demo.exception.ServiceExceptionEnum; import com.example.demo.mapper.OrderMapper; import com.example.demo.service.OrderService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class OrderServiceImpl extends ServiceImplimplements OrderService { @Autowired private OrderMapper orderMapper; @Override public void saveOrder(Order order) { if(orderMapper.insert(order) <= 0){ throw new SXException(ServiceExceptionEnum.DATA_INSERT_EXCEPTION); } } }
package com.example.demo.service.impl; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.example.demo.entity.Order; import com.example.demo.entity.Stock; import com.example.demo.mapper.StockMapper; import com.example.demo.service.OrderService; import com.example.demo.service.StockService; import com.example.demo.utils.IdGenerate; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.Date; import java.util.List; @Service @Slf4j public class StockServiceImpl extends ServiceImpl配置rabbitmq的实现方式以及redis的实现方式implements StockService { @Autowired private StockMapper stockMapper; @Autowired private OrderService orderService; @Override public void decrByStock(String name) { List stockList = stockMapper.selectList(new QueryWrapper ().lambda().eq(Stock::getName, name)); stockList.forEach(stock -> { //货物购买 stock.setStock(String.valueOf(Integer.parseInt(stock.getStock())-1)); stockMapper.updateById(stock); }); } @Override public Integer selectByName(String name) { //查询存货数量 Integer stockNum = 0; List stockList = stockMapper.selectList(new QueryWrapper ().lambda().eq(Stock::getName, name)); if(stockList.size() > 0){ stockNum = Integer.parseInt(stockList.get(0).getStock()); } return stockNum; } @Override public String secDatabase(String userName, String stockName) { log.info("参加秒杀的用户是:{},秒杀的商品是:{}", userName, stockName); String message = null; //查找该商品库存 Integer stockCount = selectByName(stockName); log.info("用户:{}参加秒杀,当前商品库存量是:{}", userName, stockCount); if (stockCount > 0) { //1、库存减一 decrByStock(stockName); //2、下订单 Order order = new Order(); order.setOrderUser(userName); order.setOrderName(stockName); order.setCreateBy(userName); order.setCreateDate(new Date()); order.setUpdateBy(userName); order.setUpdateDate(new Date()); order.setDelFlag("0"); order.setId(IdGenerate.generateId()); orderService.saveOrder(order); log.info("用户:{}.参加秒杀结果是:成功", userName); message = userName + "参加秒杀结果是:成功"; } else { log.info("用户:{}.参加秒杀结果是:秒杀已经结束", userName); message = userName + "参加秒杀活动结果是:秒杀已经结束"; } return message; } }
- 订单的消费队列
package com.example.demo.service.impl;
import com.example.demo.config.RabbitMqConfig;
import com.example.demo.entity.Order;
import com.example.demo.service.OrderService;
import com.example.demo.utils.IdGenerate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Date;
@Service
@Slf4j
public class MQOrderServiceImpl {
@Autowired
private OrderService orderService;
@RabbitListener(queues = RabbitMqConfig.ORDER_QUEUE)
public void saveOrder(Order order) {
log.info("收到订单消息,订单用户为:{},商品名称为:{}", order.getOrderUser(), order.getOrderName());
order.setCreateBy(order.getOrderUser());
order.setCreateDate(new Date());
order.setUpdateBy(order.getOrderUser());
order.setUpdateDate(new Date());
order.setDelFlag("0");
order.setId(IdGenerate.generateId());
orderService.saveOrder(order);
}
}
- 库存得消费队列
package com.example.demo.service.impl;
import com.example.demo.config.RabbitMqConfig;
import com.example.demo.entity.Order;
import com.example.demo.service.StockService;
import com.example.demo.utils.IdGenerate;
import com.example.demo.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Date;
@Service
@Slf4j
public class MQStockServiceImpl {
@Autowired
private StockService stockService;
@Autowired
private RabbitTemplate rabbitTemplate;
@Autowired
private RedisUtil redisUtil;
@RabbitListener(queues = RabbitMqConfig.STORY_QUEUE)
public void decrByStock(String name) {
log.info("库存消息队列收到的消息商品信息是:{}", name);
// 调用数据库service给数据库对应商品库存减一
stockService.decrByStock(name);
}
public String secKill(String userName, String stockName) {
log.info("参加秒杀的用户是:{},秒杀的商品是:{}", userName, stockName);
String message = "";
// 1.调用redis给相应商品库存量减1
Long decrByResult = redisUtil.decrBy(stockName);
if (decrByResult >= 0) {
// 2.说明该商品的库存量有剩余,可以进行下订单操作
log.info("用户:{}秒杀该商品:{}库存有余,可以进行下订单操作", userName, stockName);
// 3.发消息给库存消息队列,将库存数据减一
rabbitTemplate.convertAndSend(RabbitMqConfig.STORY_EXCHANGE, RabbitMqConfig.STORY_ROUTING_KEY, stockName);
// 4.发消息给订单消息队列,创建订单
Order order = new Order();
order.setOrderName(stockName);
order.setOrderUser(userName);
rabbitTemplate.convertAndSend(RabbitMqConfig.ORDER_EXCHANGE, RabbitMqConfig.ORDER_ROUTING_KEY, order);
message = "用户" + userName + "秒杀" + stockName + "成功";
} else {
// 5.说明该商品的库存量没有剩余,直接返回秒杀失败的消息给用户
log.info("用户:{}秒杀时商品的库存量没有剩余,秒杀结束", userName);
message = "用户:" + userName + "商品的库存量没有剩余,秒杀结束";
}
return message;
}
}
工具类
RabbitMQConfig插件配置
package com.example.demo.config;
import org.springframework.amqp.core.*;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitMqConfig {
public static final String STORY_EXCHANGE = "STORY_EXCHANGE";
public static final String ORDER_EXCHANGE = "ORDER_EXCHANGE";
public static final String STORY_QUEUE = "STORY_QUEUE";
public static final String ORDER_QUEUE = "ORDER_QUEUE";
public static final String STORY_ROUTING_KEY = "STORY_ROUTING_KEY";
public static final String ORDER_ROUTING_KEY = "ORDER_ROUTING_KEY";
@Bean
public MessageConverter messageConverter() {
return new Jackson2JsonMessageConverter();
}
@Bean
public Exchange getStoryExchange() {
return ExchangeBuilder.directExchange(STORY_EXCHANGE).durable(true).build();
}
@Bean
public Queue getStoryQueue() {
return new Queue(STORY_QUEUE, true);
}
@Bean
public Binding bindStory() {
return BindingBuilder.bind(getStoryQueue()).to(getStoryExchange()).with(STORY_ROUTING_KEY).noargs();
}
@Bean
public Queue getOrderQueue() {
return new Queue(ORDER_QUEUE);
}
@Bean
public Exchange getOrderExchange() {
return ExchangeBuilder.directExchange(ORDER_EXCHANGE).durable(true).build();
}
@Bean
public Binding bindOrder() {
return BindingBuilder.bind(getOrderQueue()).to(getOrderExchange()).with(ORDER_ROUTING_KEY).noargs();
}
}
redis 缓存配置
package com.example.demo.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
@EnableCaching // 启用缓存,这个注解很重要;
public class RedisCacheConfig {
@Autowired
private RedisConnectionFactory redisConnectionFactory;
@Bean
public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
RedisCacheManager redisCacheManager = RedisCacheManager.builder(connectionFactory).build();
return redisCacheManager;
}
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
// 使用Jackson2JsonRedisSerialize 替换默认序列化
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
// 设置value的序列化规则和 key的序列化规则
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new StringRedisSerializer());
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
@Bean
public HashOperations hashOperations(RedisTemplate redisTemplate) {
return redisTemplate.opsForHash();
}
@Bean
public ListOperations listOperations(RedisTemplate redisTemplate) {
return redisTemplate.opsForList();
}
@Bean
public RedisMessageListenerContainer redisMessageListenerContainer() {
RedisMessageListenerContainer redisMessageListenerContainer = new RedisMessageListenerContainer();
redisMessageListenerContainer.setConnectionFactory(redisConnectionFactory);
return redisMessageListenerContainer;
}
}
package com.example.demo.utils; import com.alibaba.fastjson.JSONObject; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.HashOperations; import org.springframework.data.redis.core.ListOperations; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.ValueOperations; import org.springframework.stereotype.Component; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; @Component public class RedisUtil控制层{ @Autowired private RedisTemplate redisTemplate; @Autowired private HashOperations hashOperations; @Autowired private ListOperations listOperations; public final static long DEFAULT_EXPIRE = 180 * 10; public final static long NOT_EXPIRE = -1; public void setValue(String key, T value) { redisTemplate.opsForValue().set(key, value); } public void setValue(String key, T value, Long time) { setValue(key, value); if (time > 0) { redisTemplate.expire(key, time, TimeUnit.SECONDS); } } public void setValue(String key, T value, Long time, TimeUnit unit) { setValue(key, value); redisTemplate.expire(key, time, unit); } public T getValue(String key) { ValueOperations valueOperations = redisTemplate.opsForValue(); return valueOperations.get(key); } public void deletevalue(String key) { redisTemplate.delete(key); } public boolean exists(String key) { if (getValue(key) == null) { return false; } else { return true; } } public boolean hmset(String key, Map map) { try { redisTemplate.opsForHash().putAll(key, map); return true; } catch (Exception e) { return false; } } public boolean hmset(String key, Map map, long time) { try { redisTemplate.opsForHash().putAll(key, map); if (time > 0) { redisTemplate.expire(key, time, TimeUnit.SECONDS); } return true; } catch (Exception e) { e.printStackTrace(); return false; } } public Map
redis+消息队列进行秒杀实现
package com.example.demo.controller;
import com.example.demo.result.RestResponse;
import com.example.demo.result.ResultGenerator;
import com.example.demo.service.StockService;
import com.example.demo.service.impl.MQStockServiceImpl;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Api(value = "SecKillController", tags = "秒杀控制层")
@Slf4j
public class SecKillController {
@Autowired
private MQStockServiceImpl mqStockService;
@Autowired
private StockService stockService;
@PostMapping(value = "sec-kill", produces = "application/json")
@ApiOperation(value = "redis+消息队列进行秒杀实现", notes = "redis+消息队列进行秒杀实现", produces = "application/json")
public RestResponse secKill(@RequestParam(value = "userName") String userName, @RequestParam(value = "stockName") String stockName) {
return ResultGenerator.genSuccessResult(mqStockService.secKill(userName, stockName));
}
@PostMapping(value = "sec-data-base", produces = "application/json;")
@ApiOperation(value = "实现纯数据库操作实现秒杀操作", notes = "实现纯数据库操作实现秒杀操作", produces = "application/json")
public RestResponse secDatabase(@RequestParam(value = "userName") String userName, @RequestParam(value = "stockName") String stockName) {
return ResultGenerator.genSuccessResult(stockService.secDatabase(userName, stockName));
}
}
启动项目
启动完成,redis中上架10个货物。
打开JMeter并发环境测试
测试计划右键,添加一个线程组
给这个线程组的数量为40,这个线程组的作用就是模拟40个用户发送请求,去秒杀;然后再在线程组右键,添加一个Http请求,这个就是我们用来发送请求的组件了
这个请求唯一要说得就是,随机参数了,因为用户名肯定不可能给40个相同得名字,这边我们利用JMeter给用户名得值为随机数
点击上方得白色小书本,选择random,1-99得随机数。
开始测试
2021-09-13 17:35:43,304 INFO [http-nio-8090-exec-10] o.a.c.c.C.[Tomcat].[localhost].[/] [DirectJDKLog.java : 173] Initializing Spring DispatcherServlet 'dispatcherServlet' 2021-09-13 17:35:43,308 INFO [http-nio-8090-exec-10] o.s.web.servlet.DispatcherServlet [frameworkServlet.java : 524] Initializing Servlet 'dispatcherServlet' 2021-09-13 17:35:43,335 INFO [http-nio-8090-exec-10] o.s.web.servlet.DispatcherServlet [frameworkServlet.java : 546] Completed initialization in 26 ms 2021-09-13 17:35:43,401 INFO [http-nio-8090-exec-10] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 60] 参加秒杀的用户是:10,秒杀的商品是:watch 2021-09-13 17:35:43,404 INFO [http-nio-8090-exec-7] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 60] 参加秒杀的用户是:29,秒杀的商品是:watch 2021-09-13 17:35:43,403 INFO [http-nio-8090-exec-6] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 60] 参加秒杀的用户是:48,秒杀的商品是:watch 2021-09-13 17:35:43,402 INFO [http-nio-8090-exec-13] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 60] 参加秒杀的用户是:74,秒杀的商品是:watch 2021-09-13 17:35:43,404 INFO [http-nio-8090-exec-9] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 60] 参加秒杀的用户是:66,秒杀的商品是:watch 2021-09-13 17:35:43,407 INFO [http-nio-8090-exec-14] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 60] 参加秒杀的用户是:59,秒杀的商品是:watch 2021-09-13 17:35:43,402 INFO [http-nio-8090-exec-16] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 60] 参加秒杀的用户是:58,秒杀的商品是:watch 2021-09-13 17:35:43,406 INFO [http-nio-8090-exec-5] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 60] 参加秒杀的用户是:83,秒杀的商品是:watch 2021-09-13 17:35:43,408 INFO [http-nio-8090-exec-17] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 60] 参加秒杀的用户是:12,秒杀的商品是:watch 2021-09-13 17:35:43,408 INFO [http-nio-8090-exec-1] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 60] 参加秒杀的用户是:75,秒杀的商品是:watch 2021-09-13 17:35:43,403 INFO [http-nio-8090-exec-2] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 60] 参加秒杀的用户是:42,秒杀的商品是:watch 2021-09-13 17:35:43,405 INFO [http-nio-8090-exec-3] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 60] 参加秒杀的用户是:72,秒杀的商品是:watch 2021-09-13 17:35:43,403 INFO [http-nio-8090-exec-11] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 60] 参加秒杀的用户是:52,秒杀的商品是:watch 2021-09-13 17:35:43,405 INFO [http-nio-8090-exec-8] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 60] 参加秒杀的用户是:32,秒杀的商品是:watch 2021-09-13 17:35:43,403 INFO [http-nio-8090-exec-12] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 60] 参加秒杀的用户是:21,秒杀的商品是:watch 2021-09-13 17:35:43,403 INFO [http-nio-8090-exec-4] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 60] 参加秒杀的用户是:67,秒杀的商品是:watch 2021-09-13 17:35:43,404 INFO [http-nio-8090-exec-15] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 60] 参加秒杀的用户是:63,秒杀的商品是:watch 2021-09-13 17:35:43,424 INFO [http-nio-8090-exec-18] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 60] 参加秒杀的用户是:48,秒杀的商品是:watch 2021-09-13 17:35:43,429 INFO [http-nio-8090-exec-10] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 66] 用户:10秒杀该商品:watch库存有余,可以进行下订单操作 2021-09-13 17:35:43,429 INFO [http-nio-8090-exec-7] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 66] 用户:29秒杀该商品:watch库存有余,可以进行下订单操作 2021-09-13 17:35:43,430 INFO [http-nio-8090-exec-6] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 66] 用户:48秒杀该商品:watch库存有余,可以进行下订单操作 2021-09-13 17:35:43,430 INFO [http-nio-8090-exec-11] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 66] 用户:52秒杀该商品:watch库存有余,可以进行下订单操作 2021-09-13 17:35:43,430 INFO [http-nio-8090-exec-14] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 66] 用户:59秒杀该商品:watch库存有余,可以进行下订单操作 2021-09-13 17:35:43,431 INFO [http-nio-8090-exec-13] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 66] 用户:74秒杀该商品:watch库存有余,可以进行下订单操作 2021-09-13 17:35:43,431 INFO [http-nio-8090-exec-2] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 66] 用户:42秒杀该商品:watch库存有余,可以进行下订单操作 2021-09-13 17:35:43,431 INFO [http-nio-8090-exec-5] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 66] 用户:83秒杀该商品:watch库存有余,可以进行下订单操作 2021-09-13 17:35:43,431 INFO [http-nio-8090-exec-17] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 66] 用户:12秒杀该商品:watch库存有余,可以进行下订单操作 2021-09-13 17:35:43,431 INFO [http-nio-8090-exec-16] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 66] 用户:58秒杀该商品:watch库存有余,可以进行下订单操作 2021-09-13 17:35:43,431 INFO [http-nio-8090-exec-1] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 78] 用户:75秒杀时商品的库存量没有剩余,秒杀结束 2021-09-13 17:35:43,431 INFO [http-nio-8090-exec-8] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 78] 用户:32秒杀时商品的库存量没有剩余,秒杀结束 2021-09-13 17:35:43,431 INFO [http-nio-8090-exec-4] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 78] 用户:67秒杀时商品的库存量没有剩余,秒杀结束 2021-09-13 17:35:43,435 INFO [http-nio-8090-exec-12] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 78] 用户:21秒杀时商品的库存量没有剩余,秒杀结束 2021-09-13 17:35:43,435 INFO [http-nio-8090-exec-3] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 78] 用户:72秒杀时商品的库存量没有剩余,秒杀结束 2021-09-13 17:35:43,436 INFO [http-nio-8090-exec-18] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 78] 用户:48秒杀时商品的库存量没有剩余,秒杀结束 2021-09-13 17:35:43,435 INFO [http-nio-8090-exec-15] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 78] 用户:63秒杀时商品的库存量没有剩余,秒杀结束 2021-09-13 17:35:43,435 INFO [http-nio-8090-exec-9] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 78] 用户:66秒杀时商品的库存量没有剩余,秒杀结束 2021-09-13 17:35:43,455 INFO [http-nio-8090-exec-19] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 60] 参加秒杀的用户是:10,秒杀的商品是:watch 2021-09-13 17:35:43,464 INFO [http-nio-8090-exec-19] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 78] 用户:10秒杀时商品的库存量没有剩余,秒杀结束 2021-09-13 17:35:43,480 INFO [http-nio-8090-exec-20] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 60] 参加秒杀的用户是:49,秒杀的商品是:watch 2021-09-13 17:35:43,487 INFO [http-nio-8090-exec-20] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 78] 用户:49秒杀时商品的库存量没有剩余,秒杀结束 2021-09-13 17:35:43,502 INFO [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#0-1] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 45] 库存消息队列收到的消息商品信息是:watch 2021-09-13 17:35:43,798 INFO [http-nio-8090-exec-30] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 60] 参加秒杀的用户是:41,秒杀的商品是:watch 2021-09-13 17:35:43,798 INFO [http-nio-8090-exec-32] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 60] 参加秒杀的用户是:85,秒杀的商品是:watch 2021-09-13 17:35:43,799 INFO [http-nio-8090-exec-24] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 60] 参加秒杀的用户是:93,秒杀的商品是:watch 2021-09-13 17:35:43,799 INFO [http-nio-8090-exec-26] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 60] 参加秒杀的用户是:1,秒杀的商品是:watch 2021-09-13 17:35:43,800 INFO [http-nio-8090-exec-25] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 60] 参加秒杀的用户是:64,秒杀的商品是:watch 2021-09-13 17:35:43,802 INFO [http-nio-8090-exec-27] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 60] 参加秒杀的用户是:0,秒杀的商品是:watch 2021-09-13 17:35:43,804 INFO [http-nio-8090-exec-28] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 60] 参加秒杀的用户是:2,秒杀的商品是:watch 2021-09-13 17:35:43,804 INFO [http-nio-8090-exec-31] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 60] 参加秒杀的用户是:21,秒杀的商品是:watch 2021-09-13 17:35:43,804 INFO [http-nio-8090-exec-23] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 60] 参加秒杀的用户是:67,秒杀的商品是:watch 2021-09-13 17:35:43,804 INFO [http-nio-8090-exec-29] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 60] 参加秒杀的用户是:52,秒杀的商品是:watch 2021-09-13 17:35:43,811 INFO [http-nio-8090-exec-30] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 78] 用户:41秒杀时商品的库存量没有剩余,秒杀结束 2021-09-13 17:35:43,815 INFO [http-nio-8090-exec-24] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 78] 用户:93秒杀时商品的库存量没有剩余,秒杀结束 2021-09-13 17:35:43,816 INFO [http-nio-8090-exec-25] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 78] 用户:64秒杀时商品的库存量没有剩余,秒杀结束 2021-09-13 17:35:43,816 INFO [http-nio-8090-exec-27] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 78] 用户:0秒杀时商品的库存量没有剩余,秒杀结束 2021-09-13 17:35:43,816 INFO [http-nio-8090-exec-28] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 78] 用户:2秒杀时商品的库存量没有剩余,秒杀结束 2021-09-13 17:35:43,816 INFO [http-nio-8090-exec-31] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 78] 用户:21秒杀时商品的库存量没有剩余,秒杀结束 2021-09-13 17:35:43,816 INFO [http-nio-8090-exec-23] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 78] 用户:67秒杀时商品的库存量没有剩余,秒杀结束 2021-09-13 17:35:43,815 INFO [http-nio-8090-exec-32] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 78] 用户:85秒杀时商品的库存量没有剩余,秒杀结束 2021-09-13 17:35:43,815 INFO [http-nio-8090-exec-26] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 78] 用户:1秒杀时商品的库存量没有剩余,秒杀结束 2021-09-13 17:35:43,816 INFO [http-nio-8090-exec-29] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 78] 用户:52秒杀时商品的库存量没有剩余,秒杀结束 2021-09-13 17:35:43,818 INFO [http-nio-8090-exec-22] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 60] 参加秒杀的用户是:45,秒杀的商品是:watch 2021-09-13 17:35:43,818 INFO [http-nio-8090-exec-33] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 60] 参加秒杀的用户是:21,秒杀的商品是:watch 2021-09-13 17:35:43,831 INFO [http-nio-8090-exec-34] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 60] 参加秒杀的用户是:99,秒杀的商品是:watch 2021-09-13 17:35:43,846 INFO [http-nio-8090-exec-22] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 78] 用户:45秒杀时商品的库存量没有剩余,秒杀结束 2021-09-13 17:35:43,848 INFO [http-nio-8090-exec-33] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 78] 用户:21秒杀时商品的库存量没有剩余,秒杀结束 2021-09-13 17:35:43,848 INFO [http-nio-8090-exec-21] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 60] 参加秒杀的用户是:34,秒杀的商品是:watch 2021-09-13 17:35:43,848 INFO [http-nio-8090-exec-4] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 60] 参加秒杀的用户是:1,秒杀的商品是:watch 2021-09-13 17:35:43,855 INFO [http-nio-8090-exec-34] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 78] 用户:99秒杀时商品的库存量没有剩余,秒杀结束 2021-09-13 17:35:43,857 INFO [http-nio-8090-exec-21] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 78] 用户:34秒杀时商品的库存量没有剩余,秒杀结束 2021-09-13 17:35:43,862 INFO [http-nio-8090-exec-4] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 78] 用户:1秒杀时商品的库存量没有剩余,秒杀结束 2021-09-13 17:35:43,877 INFO [http-nio-8090-exec-31] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 60] 参加秒杀的用户是:32,秒杀的商品是:watch 2021-09-13 17:35:43,887 INFO [http-nio-8090-exec-31] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 78] 用户:32秒杀时商品的库存量没有剩余,秒杀结束 2021-09-13 17:35:43,900 INFO [http-nio-8090-exec-20] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 60] 参加秒杀的用户是:68,秒杀的商品是:watch 2021-09-13 17:35:43,907 INFO [http-nio-8090-exec-20] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 78] 用户:68秒杀时商品的库存量没有剩余,秒杀结束 2021-09-13 17:35:43,925 INFO [http-nio-8090-exec-13] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 60] 参加秒杀的用户是:26,秒杀的商品是:watch 2021-09-13 17:35:43,929 INFO [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#1-1] c.e.d.s.impl.MQOrderServiceImpl [MQOrderServiceImpl.java : 33] 收到订单消息,订单用户为:58,商品名称为:watch 2021-09-13 17:35:43,933 INFO [http-nio-8090-exec-13] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 78] 用户:26秒杀时商品的库存量没有剩余,秒杀结束 2021-09-13 17:35:43,948 INFO [http-nio-8090-exec-9] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 60] 参加秒杀的用户是:52,秒杀的商品是:watch 2021-09-13 17:35:43,955 INFO [http-nio-8090-exec-9] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 78] 用户:52秒杀时商品的库存量没有剩余,秒杀结束 2021-09-13 17:35:43,973 INFO [http-nio-8090-exec-6] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 60] 参加秒杀的用户是:96,秒杀的商品是:watch 2021-09-13 17:35:43,981 INFO [http-nio-8090-exec-6] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 78] 用户:96秒杀时商品的库存量没有剩余,秒杀结束 2021-09-13 17:35:44,118 INFO [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#0-1] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 45] 库存消息队列收到的消息商品信息是:watch 2021-09-13 17:35:44,118 INFO [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#1-1] c.e.d.s.impl.MQOrderServiceImpl [MQOrderServiceImpl.java : 33] 收到订单消息,订单用户为:52,商品名称为:watch 2021-09-13 17:35:44,126 INFO [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#0-1] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 45] 库存消息队列收到的消息商品信息是:watch 2021-09-13 17:35:44,134 INFO [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#0-1] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 45] 库存消息队列收到的消息商品信息是:watch 2021-09-13 17:35:44,135 INFO [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#1-1] c.e.d.s.impl.MQOrderServiceImpl [MQOrderServiceImpl.java : 33] 收到订单消息,订单用户为:29,商品名称为:watch 2021-09-13 17:35:44,143 INFO [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#0-1] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 45] 库存消息队列收到的消息商品信息是:watch 2021-09-13 17:35:44,151 INFO [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#0-1] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 45] 库存消息队列收到的消息商品信息是:watch 2021-09-13 17:35:44,151 INFO [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#1-1] c.e.d.s.impl.MQOrderServiceImpl [MQOrderServiceImpl.java : 33] 收到订单消息,订单用户为:42,商品名称为:watch 2021-09-13 17:35:44,160 INFO [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#0-1] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 45] 库存消息队列收到的消息商品信息是:watch 2021-09-13 17:35:44,169 INFO [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#1-1] c.e.d.s.impl.MQOrderServiceImpl [MQOrderServiceImpl.java : 33] 收到订单消息,订单用户为:59,商品名称为:watch 2021-09-13 17:35:44,169 INFO [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#0-1] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 45] 库存消息队列收到的消息商品信息是:watch 2021-09-13 17:35:44,187 INFO [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#0-1] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 45] 库存消息队列收到的消息商品信息是:watch 2021-09-13 17:35:44,192 INFO [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#1-1] c.e.d.s.impl.MQOrderServiceImpl [MQOrderServiceImpl.java : 33] 收到订单消息,订单用户为:83,商品名称为:watch 2021-09-13 17:35:44,194 INFO [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#0-1] c.e.d.s.impl.MQStockServiceImpl [MQStockServiceImpl.java : 45] 库存消息队列收到的消息商品信息是:watch 2021-09-13 17:35:44,208 INFO [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#1-1] c.e.d.s.impl.MQOrderServiceImpl [MQOrderServiceImpl.java : 33] 收到订单消息,订单用户为:10,商品名称为:watch 2021-09-13 17:35:44,223 INFO [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#1-1] c.e.d.s.impl.MQOrderServiceImpl [MQOrderServiceImpl.java : 33] 收到订单消息,订单用户为:12,商品名称为:watch 2021-09-13 17:35:44,239 INFO [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#1-1] c.e.d.s.impl.MQOrderServiceImpl [MQOrderServiceImpl.java : 33] 收到订单消息,订单用户为:48,商品名称为:watch 2021-09-13 17:35:44,254 INFO [org.springframework.amqp.rabbit.RabbitListenerEndpointContainer#1-1] c.e.d.s.impl.MQOrderServiceImpl [MQOrderServiceImpl.java : 33] 收到订单消息,订单用户为:74,商品名称为:watch
秒杀完成了,但是redis中出现超卖现象。
存在超卖问题,正在优化中,后续继续更新…
源码:码云仓库
访问地址:https://gitee.com/kai-java/sec-kill
git地址:https://gitee.com/kai-java/sec-kill.git
所有内容皆为个人总结或转载别人的文章,只为学习技术。 若您觉得文章有用,欢迎点赞分享! 若无意对您的文章造成侵权,请您留言,博主看到后会及时处理,谢谢。



