Login
网站首页 > 文章中心 > 其它

SpringBoot◆redis◆activemq秒杀场景简单整理

作者:小编 更新时间:2023-09-27 16:17:50 浏览量:419人看过

目前设想的大致的序列图

秒杀开始前,初始化数据库秒杀信息,并同步到redis缓存中,秒杀开始后,用户直接访问redis缓存进行库存扣减,当剩余库存小于0时说明商品抢购完毕,直接返回库存不足抢购失败,抢购成功的用户返回"秒杀成功,订单处理中,请稍后查看",并且成功的抢购信息进入队列,异步扣减数据库实际库存并下单.用户查询订单,根据用户和商品查询对应的订单信息返回给用户.

SpringBoot◆redis◆activemq秒杀场景简单整理

①.、减订单sql:

准备

JMeter:用于模拟多线程用户秒杀

ActiveMQ:消息队列

redis:缓存

mysql:数据库

环境搭建(前面已经介绍了springboot◆mybatis◆druid◆activemq◆redis的整合)

mysql创建表? tproduct-商品? torder-订单

启动redis和activemq

pom.xml


xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/④0.0" xmlns:xsi="http://www.w③org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/④0.0 http://maven.apache.org/xsd/maven-④0.0.xsd">
<modelVersion>④0.0modelVersion>
<parent>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-starter-parentartifactId>
    <version>2.1.④RELEASEversion>
    <relativePath/> 
parent>
<groupId>com.examplegroupId>
<artifactId>test2artifactId>
<version>0.0.1-SNAPSHOTversion>
<name>test2name>
<description>Demo project for Spring Bootdescription>

<properties>
    <java.version>1.8java.version>
properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-webartifactId>
    dependency>

    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-testartifactId>
        <scope>testscope>
    dependency>

    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-activemqartifactId>
    dependency>

    <dependency>
        <groupId>mysqlgroupId>
        <artifactId>mysql-connector-javaartifactId>
        <version>⑤1.38version>
    dependency>
    <dependency>
        <groupId>org.mybatis.spring.bootgroupId>
        <artifactId>mybatis-spring-boot-starterartifactId>
        <version>1.③2version>
    dependency>
    <dependency>
        <groupId>com.alibabagroupId>
        <artifactId>druid-spring-boot-starterartifactId>
        <version>1.1.10version>
    dependency>

    
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-data-redisartifactId>
    dependency>
dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-maven-pluginartifactId>
        plugin>
    plugins>
build>

project>

application.properties


#tomcat 配置 默认8080 可以改成其他端口,这里显式配置
server.port=8080
#activemq 配置 用户名密码 用默认值
spring.activemq.broker-url=tcp://0.0.0.0:61616
#spring.jms.template.default-destination=test-queue
spring.jms.template.default-destination=flash-queue

#druid数据源
spring.datasource.druid.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.druid.url=jdbc:mysql://192.16⑧1.104:3306/test?useUnicode=truecharacterEncoding=utf-8
spring.datasource.druid.username=root
spring.datasource.druid.password=root
#数据库连接池配置
spring.datasource.druid.initial-size=5
spring.datasource.druid.max-active=20
spring.datasource.druid.min-idle=5
spring.datasource.druid.max-wait=30000

#mybatis
mybatis.mapper-locations=classpath:mapper/*.xml
#mybatis.type-aliases-package=com.flysand.demo.entity

#redis配置
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=192.16⑧1.113
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=test123
# 连接池最大连接数(使用负值表示没有限制)
# spring boot 1版本配置
#spring.redis.pool.max-active=8
#spring boot 2 版本配置
spring.redis.jedis.pool.max-active=10
# 连接池最大阻塞等待时间(使用负值表示没有限制)
#spring.redis.pool.max-wait=-1ms
spring.redis.jedis.pool.max-wait=-1
# 连接池中的最大空闲连接
#spring.redis.pool.max-idle=8
spring.redis.jedis.pool.max-idle=8
# 连接池中的最小空闲连接
#spring.redis.pool.min-idle=0
spring.redis.jedis.pool.min-idle=0
# 连接超时时间(毫秒)
spring.redis.timeout=2000ms


#默认logback日志配置
#日志文件配置 path为空,则在项目根目录 file为空,则默认为spring.log
logging.path=
logging.file=test2.log
#日志级别 root级别
logging.level.root=info
#自定义包日志级别
logging.level.com.flysand=debug
#格式 - 控制台
logging.pattern.console=[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%thread] - [%-5level][%logger{50}:%line] - %msg%n
#文件  日期默认格式yyyy-MM-dd HH:mm:ss.SSS
logging.pattern.file=[%d{yyyy-MM-dd HH:mm:ss.SSS}] [%thread] - [%-5level][%logger{50}:%line] - %msg%n

ProductServiceImpl.java


package com.flysand.demo.service.impl;

import com.flysand.demo.activemq.ActiveMqProducer;
import com.flysand.demo.dao.TProductMapper;
import com.flysand.demo.entity.TProduct;
import com.flysand.demo.service.ProductService;
import com.flysand.demo.util.RedisUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @author flysand on 2019/04/18
 **/
@Service
public class ProductServiceImpl implements ProductService {

private static final Logger logger = LoggerFactory.getLogger(ProductServiceImpl.class);

@Autowired
private TProductMapper tProductMapper;

@Autowired
private RedisUtils redisUtils;

@Autowired
private ActiveMqProducer producer;

@Override
public int createProduct(TProduct product) {
    return tProductMapper.insert(product);
}

@Override
public int decreaseProduct(String productId) {
    return tProductMapper.decreaseById(productId);
}

@Override
public int getStockById(String productId) {
    return tProductMapper.selectProductStock(productId);
}

@Override
public TProduct getProductById(String productId) {
    return tProductMapper.selectById(productId);
}

@Override
public String syncStock(String productId) {
    String result = "同步库存成功";
    try {
        int count = tProductMapper.selectProductStock(productId);
        redisUtils.setString(productId, String.valueOf(count));
    } catch (Exception e) {
        logger.error("同步库存异常:{}", e.getMessage());
        result = "同步库存异常";
    }
    return result;
}

@Override
public String flash(String key) {
    String result = "抢购提交成功,订单处理中";
    // 原子减1
    long count = (long) redisUtils.increase(key, -1L);
    String name = Thread.currentThread().getName();
    // 把redis减1后还大于0即还有库存的设为抢购成功,并放入成功队列
    if (count >= 0) {
        result ◆= ",抢购线程" ◆ name ◆ ",抢购1个,剩余" ◆ count;
        //redisUtils.sset("success", name);
        // 推送队列
        String msg = key ◆ "," ◆ name;
        producer.sendMessage(msg);
    } else {
        result = "库存不足,抢购失败" ◆ name;
        //   redisUtils.sset("fail", name);
        }
    return result;
}
}

ActiveMqConsumer.java


package com.flysand.demo.activemq;

import com.flysand.demo.entity.TOrder;
import com.flysand.demo.entity.TProduct;
import com.flysand.demo.service.OrderService;
import com.flysand.demo.service.ProductService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.Date;
import java.util.Random;

/**
 * @author flysand on 2019/04/11
 **/
@Component
public class ActiveMqConsumer {

private static final Logger logger = LoggerFactory.getLogger(ActiveMqConsumer.class);

@Autowired
private ProductService productService;

@Autowired
private OrderService orderService;

@JmsListener(destination = "test-queue")
public void receiveMessage(String text) {
    System.out.println("消费消息:" ◆ text);
}

@JmsListener(destination = "flash-queue")
public void invokeFlash(String text) {
    logger.debug("执行秒杀后的下单操作");
    String productId = text.split(",")[0];
    String threadName = text.split(",")[1];
    // 查询当前商品库存
    TProduct product = productService.getProductById(productId);
    if (product == null || product.getpCount() <= 0) {
        logger.error("商品不存在或库存不足");
    } else {
        // 减少库存,并下单
            productService.decreaseProduct(productId);
        TOrder order = new TOrder();
        long time = System.currentTimeMillis();
        order.setOrderNo("P_" ◆ time);
        order.setProductId(productId);
        order.setQuantity(BigDecimal.ONE);
        order.setTotalAmount(product.getUnitPrice().multiply(BigDecimal.ONE));
        order.setThreadName(threadName);
        orderService.createOrder(order);
    }
}


}

测试

后续增加多商品,以及下单信息回传队列,增加异常订单推送,以及websocket直接响应结果给前台.

git?源码:https://github.com/symflysand/secendsKill

以上就是土嘎嘎小编为大家整理的SpringBoot◆redis◆activemq秒杀场景简单整理相关主题介绍,如果您觉得小编更新的文章只要能对粉丝们有用,就是我们最大的鼓励和动力,不要忘记讲本站分享给您身边的朋友哦!!

版权声明:倡导尊重与保护知识产权。未经许可,任何人不得复制、转载、或以其他方式使用本站《原创》内容,违者将追究其法律责任。本站文章内容,部分图片来源于网络,如有侵权,请联系我们修改或者删除处理。

编辑推荐

热门文章