实现基于SpringBoot+Maven+Mysql+Redis+RabbitMQ 的高并发秒杀系统(限时秒杀)

基于 SpringBoot+Mybatis+Redis+RabbitMQ 秒杀系统 开发工具 idea 2017.2.3 开发环境 JDK Maven Mysql SpringBoot redis RabbitMQ 1.8 3.2.2 5.7 1.5.10.RELEASE 3.2 项目启动说明 1、启动前,请配置 application.properties 中相关redis、mysql、ra... 阅读详情

原理:

秒杀与其他业务最大的区别在于,在秒杀的瞬间,系统的并发量和吞吐量会非常大,与此同时,网络的流量也会瞬间变大。

对于网络流量瞬间变大问题,最常用的办法就是将页面静态化,也就是我们常说的前后端分离。把静态页面直接缓存到用户的浏览器中,当用户需要获取数据时,就从服务端接口动态获取。这样会大大节省网络的流量,如果再加上CDN优化,一般都不会有大问题。

对于系统并发量变大问题,这里的核心在于如何在大并发的情况下保证数据库能扛得住压力,因为大并发的瓶颈在于数据库。如果用户的请求直接从前端传到数据库,显然,数据库是无法承受几十万上百万甚至上千万的并发量的。因此,我们能做的只能是减少对数据库的访问。例如,前端发出了100万个请求,通过我们的处理,最终只有10个会访问数据库,这样就会大大提升系统性能。再针对秒杀这种场景,因为秒杀商品的数量是有限的,因此这种做法刚好适用。

那么具体是如何来减少对数据库的访问的呢?

假如,某个商品可秒杀的数量是10,那么在秒杀活动开始之前,把商品的ID和数量加载到Redis缓存。当服务端收到请求时,首先预减Redis中的数量,如果数量减到小于0时,那么随后的访问直接返回秒杀失败的信息。也就是说,最终只有10个请求会去访问数据库。

如果商品数量比较多,比如1万件商品参与秒杀,那么就有1万*10=10万个请求并发去访问数据库,数据库的压力还是会很大。这里就用到了另外一个非常重要的组件:消息队列。我们不是把请求直接去访问数据库,而是先把请求写到消息队列中,做一个缓存,然后再去慢慢的更新数据库。这样做之后,前端用户的请求可能不会立即得到响应是成功还是失败,很可能得到的是一个排队中的返回值,这个时候,需要客户端去服务端轮询,因为我们不能保证一定就秒杀成功了。当服务端出队,生成订单以后,把用户ID和商品ID写到缓存中,来应对客户端的轮询就可以了。

这样处理以后,我们的应用是可以很简单的进行分布式横向扩展的,以应对更大的并发。

当然,秒杀系统还有很多要处理的事情,比如限流防刷、分布式Session等等。

1.搭建项目环境

下方提供了安装工具的博客

1.1 安装RabbitMQ

https://blog.youkuaiyun.com/m0_37034294/article/details/82839494

2.2 安装Redis+RedisDesktopManager

https://blog.youkuaiyun.com/qq_39135287/article/details/82686837

2.3 Jmeter压力测试工具

https://blog.youkuaiyun.com/liuyanh2006/article/details/82494548

2.4 创建数据库表结构

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

注意:请将主键设为自动增长

2.项目代码

1.创建一个springboot项目,启动器可先不选择,下方直接放pom.xml文件,cv即可。


    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>org.junit.vintage</groupId>
                <artifactId>junit-vintage-engine</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-devtools</artifactId>
        <scope>runtime</scope>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.8.1</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
        <version>0.7.0</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.1.0</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
    </dependency>
    <dependency>
        <groupId>tk.mybatis</groupId>
        <artifactId>mapper-spring-boot-starter</artifactId>
        <version>2.0.3-beta1</version>
    </dependency>
    <dependency>
        <groupId>tk.mybatis</groupId>
        <artifactId>mapper</artifactId>
        <version>4.0.0</version>
    </dependency>

2.配置application.properties文件


spring.devtools.restart.enabled=false
##配置数据库连接
spring.datasource.username=root
spring.datasource.password=root
server.port=8443
spring.datasource.url=jdbc:mysql://localhost:3306/myredis?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&allowMultiQueries=true
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

##配置rabbitmq连接
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest

#JPA Configuration:
spring.jpa.database-platform=org.hibernate.dialect.MySQLDialect

##配置连接redis --都记得打开服务
spring.redis.host=localhost
spring.redis.port=6379 
spring.redis.jedis.pool.max-active=1024
spring.redis.jedis.pool.max-wait=-1s
spring.redis.jedis.pool.max-idle=200
spring.redis.password=123456
  1. 新建pojo包,添加实体类

    本次数据库操作方面使用了tkmybatis框架,所以实体类我们需要用到JPA的注解,来实现映射关系。

    
    import java.io.Serializable;
    import lombok.Data;
    import javax.persistence.Column;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.persistence.Table;
    @Data
    @Table(name = "t_order")
    public class Order implements Serializable {
        private static final long serialVersionUID = -8867272732777764701L;
    
        @Id
        @Column(name = "id")
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
    
        @Column(name = "order_name")
        private String order_name;
    
        @Column(name = "order_user")
        private String order_user;
    }
    
    
    import lombok.Data;
    import javax.persistence.Column;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.persistence.Table;
    import java.io.Serializable;
    @Table(name = "stock")
    @Data
    public class Stock implements Serializable {
        private static final long serialVersionUID = 2451194410162873075L;
    
        @Id
        @Column(name = "id")
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
    
        @Column(name = "name")
        private String name;
    
        @Column(name = "stock")
        private Long stock;
    }
    
  2. 配置tkmybatis的接口

​ 4.1 需要通过继承它来实现数据库操作

  1. 2新建名为base的包,在base下面新建service的接口

  2. 3新建GenericMapper接口

import tk.mybatis.mapper.common.Mapper;
import tk.mybatis.mapper.common.MySqlMapper;

public interface GenericMapper<T> extends Mapper<T>, MySqlMapper<T> {
}

在这里插入图片描述

  1. 新建mapper层

OrderMapper.java

import com.demo.base.service.GenericMapper;
import com.demo.pojo.Order;

public interface OrderMapper extends GenericMapper<Order> {
    void insertOrder(Order order);
}
    

StockMapper.java

import com.demo.base.service.GenericMapper;
import com.demo.pojo.Stock;

public interface StockMapper extends GenericMapper<Stock> {
}

在这里插入图片描述

  1. 编写RabbitMQ和redis的配置类
    新建config包,新建redis和RabbitMQ的类
package com.demo.config;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.Exchange;
import org.springframework.amqp.core.ExchangeBuilder;
import org.springframework.amqp.core.Queue;
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 MyRabbitMQConfig {

    //库存交换机
    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);
    }
    //库存交换机和库存队列绑定
    @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();
    }
}
package com.demo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
    // 配置redis得配置详解
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
        template.setConnectionFactory(redisConnectionFactory);
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.setHashKeySerializer(new GenericJackson2JsonRedisSerializer());
        template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        template.afterPropertiesSet();
        return template;
    }
}

在这里插入图片描述

  1. 编写service层
    新建service包以及impl包,这里只提供实现类
import com.demo.mapper.OrderMapper;
import com.demo.pojo.Order;
import com.demo.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class OrderServiceImpl implements OrderService {
    @Autowired
    private OrderMapper orderMapper;
    @Override
    public void createOrder(Order order) {
        orderMapper.insert(order);
    }
}
package com.demo.service.impl;
import com.demo.mapper.StockMapper;
import com.demo.pojo.Stock;
import com.demo.service.StockService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;
import java.util.List;
@Service
public class StockServiceImpl implements StockService {
    @Autowired
    private StockMapper stockMapper;
    // 秒杀商品后减少库存
    @Override
    public void decrByStock(String stockName) {
        Example example = new Example(Stock.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("name", stockName);
        List<Stock> stocks = stockMapper.selectByExample(example);
        if (!CollectionUtils.isEmpty(stocks)) {
            Stock stock = stocks.get(0);
            stock.setStock(stock.getStock() - 1);
            stockMapper.updateByPrimaryKey(stock);
        }
    }
    // 秒杀商品前判断是否有库存
    @Override
    public Integer selectByExample(String stockName) {
        Example example = new Example(Stock.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("name", stockName);
        List<Stock> stocks = stockMapper.selectByExample(example);
        if (!CollectionUtils.isEmpty(stocks)) {
            return stocks.get(0).getStock().intValue();
        }
        return 0;
    }
}
  1. 继续在 service包下面新建

    MQOrderService.java

package com.demo.service;

import com.demo.config.MyRabbitMQConfig;
import com.demo.pojo.Order;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/*订单的消费队列*/
@Service
@Slf4j
public class MQOrderService {
    @Autowired
    private OrderService orderService;
    /**
     * 监听订单消息队列,并消费
     *
     * @param order
     */
    @RabbitListener(queues = MyRabbitMQConfig.ORDER_QUEUE)
    public void createOrder(Order order) {
        log.info("收到订单消息,订单用户为:{},商品名称为:{}", order.getOrder_user(), order.getOrder_name());
        /**
         * 调用数据库orderService创建订单信息
         */
        orderService.createOrder(order);
    }
}

MQStockService.java

package com.demo.service;

import com.demo.config.MyRabbitMQConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/*消费队列*/
@Service
@Slf4j
public class MQStockService {
    @Autowired
    private StockService stockService;
    /**
     * 监听库存消息队列,并消费
     * @param stockName
     */
    @RabbitListener(queues = MyRabbitMQConfig.STORY_QUEUE)
    public void decrByStock(String stockName) {
        log.info("库存消息队列收到的消息商品信息是:{}", stockName);
        /**
         * 调用数据库service给数据库对应商品库存减一
         */
        stockService.decrByStock(stockName);
    }
}

RedisService.java

**主要用来实现对redis得key和value初始化以及对value得操作** 
package com.demo.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.concurrent.TimeUnit;
@Service
public class RedisService {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    /**
     * 设置String键值对
     * @param key
     * @param value
     * @param millis
     */
    public void put(String key, Object value, long millis) {
        redisTemplate.opsForValue().set(key, value, millis, TimeUnit.MINUTES);
    }
    public void putForHash(String objectKey, String hkey, String value) {
        redisTemplate.opsForHash().put(objectKey, hkey, value);
    }
    public <T> T get(String key, Class<T> type) {
        return (T) redisTemplate.boundValueOps(key).get();
    }
    public void remove(String key) {
        redisTemplate.delete(key);
    }
    public boolean expire(String key, long millis) {
        return redisTemplate.expire(key, millis, TimeUnit.MILLISECONDS);
    }
    public boolean persist(String key) {
        return redisTemplate.hasKey(key);
    }
    public String getString(String key) {
        return (String) redisTemplate.opsForValue().get(key);
    }
    public Integer getInteger(String key) {
        return (Integer) redisTemplate.opsForValue().get(key);
    }
    public Long getLong(String key) {
        return (Long) redisTemplate.opsForValue().get(key);
    }
    public Date getDate(String key) {
        return (Date) redisTemplate.opsForValue().get(key);
    }

    /**
     * 对指定key的键值减一
     * @param key
     * @return
     */
    public Long decrBy(String key) {
        return redisTemplate.opsForValue().decrement(key);
    }
}

​ 下面为service包得完整目录

在这里插入图片描述
10. 新建controller层,添加SecController.java,包含两种方法,参考下面的代码

```java
import com.demo.config.MyRabbitMQConfig;
import com.demo.pojo.Order;
import com.demo.service.OrderService;
import com.demo.service.RedisService;
import com.demo.service.StockService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@Slf4j
public class SecController {
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private RedisService redisService;
    @Autowired
    private OrderService orderService;
    @Autowired
    private StockService stockService;
    /**
     * 使用redis+消息队列进行秒杀实现
     *
     * @param username
     * @param stockName
     * @return
     */
    @PostMapping( value = "/sec",produces = "application/json;charset=utf-8")
    @ResponseBody
    public String sec(@RequestParam(value = "username") String username, @RequestParam(value = "stockName") String stockName) {

        log.info("参加秒杀的用户是:{},秒杀的商品是:{}", username, stockName);
        String message = null;
        //调用redis给相应商品库存量减一
        Long decrByResult = redisService.decrBy(stockName);
        if (decrByResult >= 0) {
            /**
             * 说明该商品的库存量有剩余,可以进行下订单操作
             */
            log.info("用户:{}秒杀该商品:{}库存有余,可以进行下订单操作", username, stockName);
            //发消息给库存消息队列,将库存数据减一
            rabbitTemplate.convertAndSend(MyRabbitMQConfig.STORY_EXCHANGE, MyRabbitMQConfig.STORY_ROUTING_KEY, stockName);

            //发消息给订单消息队列,创建订单
            Order order = new Order();
            order.setOrder_name(stockName);
            order.setOrder_user(username);
            rabbitTemplate.convertAndSend(MyRabbitMQConfig.ORDER_EXCHANGE, MyRabbitMQConfig.ORDER_ROUTING_KEY, order);
            message = "用户" + username + "秒杀" + stockName + "成功";
        } else {
            /**
             * 说明该商品的库存量没有剩余,直接返回秒杀失败的消息给用户
             */
            log.info("用户:{}秒杀时商品的库存量没有剩余,秒杀结束", username);
            message = "用户:"+ username + "商品的库存量没有剩余,秒杀结束";
        }
        return message;
    }

    /**
     * 实现纯数据库操作实现秒杀操作
     * @param username
     * @param stockName
     * @return
     */
    @RequestMapping("/secDataBase")
    @ResponseBody
    public String secDataBase(@RequestParam(value = "username") String username, @RequestParam(value = "stockName") String stockName) {
        log.info("参加秒杀的用户是:{},秒杀的商品是:{}", username, stockName);
        String message = null;
        //查找该商品库存
        Integer stockCount = stockService.selectByExample(stockName);
        log.info("用户:{}参加秒杀,当前商品库存量是:{}", username, stockCount);
        if (stockCount > 0) {
            /**
             * 还有库存,可以进行继续秒杀,库存减一,下订单
             */
            //1、库存减一
            stockService.decrByStock(stockName);
            //2、下订单
            Order order = new Order();
            order.setOrder_user(username);
            order.setOrder_name(stockName);
            orderService.createOrder(order);
            log.info("用户:{}.参加秒杀结果是:成功", username);
            message = username + "参加秒杀结果是:成功";
        } else {
            log.info("用户:{}.参加秒杀结果是:秒杀已经结束", username);
            message = username + "参加秒杀活动结果是:秒杀已经结束";
        }
        return message;
    }

}
```

11. 编写springboot启动类,对redis进行初始化,**简而言之就是调用我们上面写得方法,新建一个redis缓存,模拟商品信息** 

    ```java
    import com.demo.service.RedisService;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.ApplicationArguments;
    import org.springframework.boot.ApplicationRunner;
    import tk.mybatis.spring.annotation.MapperScan;
    @MapperScan("com.demo.mapper")
    @SpringBootApplication
    public class DemoApplication  implements ApplicationRunner{
    
        public static void main(String[] args) {
            SpringApplication.run(DemoApplication.class, args);
        }
        @Autowired
        private RedisService redisService;
        /**
         * redis初始化商品的库存量和信息
         * @param args
         * @throws Exception
         */
        @Override
        public void run(ApplicationArguments args) throws Exception {
            redisService.put("watch", 10, 20);
        }
    }
    ```

    12. 至此,代码已全部写完,下图为项目目录,下面进入测试步骤,请检查以上步骤是否出错!

        [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T5smGH7i-1577175164825)(C:\Users\WuLian\Pictures\1\QQ图片20191224144222.png)]

3.测试项目

  1. 启动springboot项目,并且打开 redis和rabbitmq的服务

  2. 打开Redis Desktop Manager工具,查看是否新建了一个redis :watch

在这里插入图片描述

  1. 打开我们得JMeter工具

3.1 选择中文

在这里插入图片描述

3.2 完成中文之后,我们在测试计划右键,添加一个线程组

在这里插入图片描述

在这里插入图片描述

3.3 给这个线程组得数量为40,这个线程组得作用就是模拟40个用户发送请求,去秒杀.然后再在线程组右键,添加一个Http请求,这个就是我们用来发送请求得组件了 

在这里插入图片描述

在这里插入图片描述

3.4 这个请求唯一要说得就是,随机参数了,因为用户名肯定不可能给40个相同得名字,**这边我们利用JMeter给用户名得值为随机数**

点击上方得白色小书本,选择random,1-99得随机数

在这里插入图片描述

3.5 然后我们把这个函数字符串复制到http得参数上面去

在这里插入图片描述

3.6 最后我们在测试计划建一个结果树,查看我们发送请求返回得消息数据
在这里插入图片描述
3.7 点击运行 在这里插入图片描述

4.测试结果

直接在run控制台查看运行结果,以及数据库表的变化。

基于SpringBoot与协同过滤算法的商品推荐系统实战指南 这次我们来看一个基于SpringBoot和协同过滤算法的商品推荐系统。这是一个典型的Java Web项目,采用前后端分离架构,后端使用SpringBoot+MyBatis,前端使用Vue.js,数据库是MySQL。项目核心是实现了基于用户的协同过滤(UserCF)和基于商品的协同过滤(ItemCF)算法,能够根据用户的历史行为数据(浏览、购买、评分)生成个性化的商品推荐列表。 对于Java开发者、在校学生或者需要快速搭建一个推荐系统Demo的团队来说,这个项目价值很高。它提供了一个完整的、可运行的代码框架, 阅读详情

相关推荐

SpringBoot+Vue家政平台毕设实战:从工程化思维到生产级实现

你有没有过这样的经历:毕业设计选题时,面对“家政服务平台”这类看似普通的题目,感觉无从下手?想用上时下流行的SpringBoot和Vue做前后端分离,却不知道如何把零散的技术点串联成一个真正能跑起来、有逻辑、能答辩的项目。网上找的源码要么是古董级的SSH,要么是只给前端或后端的半成品,接口对不上,环境配不通,最后时间耗尽,只能交一个漏洞百出的“演示系统”。 这恰恰是大多数计算机专业学生做毕设时的真实困境:技术栈都知道,但缺乏一个从零到一的、完整的、可落地的工程化实践。今天,我们不谈空洞的概念,就以一个 基于

weixin_34226182的博客 325

SpringBoot+Mysql+Redis+RabbitMQ实现高并发秒杀

SpringBoot+Mysql+Redis+RabbitMQ实现高并发秒杀 应用场景 ​ 商城对某一商品进行秒杀活动,该项目实例中,商品为watch,库存为10,使用jemter测试工具来模拟高并发场景 搭建项目环境 开始本次测试之前,先说本次我们项目需要安装得工具以及环境,下方我提供了安装工具得博客 安装RabbitMQ 关于RabbitMQ我得上篇博客介绍得比较详细,这里也给一个安装路径 R...

Campione_he的博客 1754

SpringBoot秒杀系统实战:高并发架构设计与Redis、MQ应用解析

高并发系统设计是后端开发的核心挑战之一,其核心在于通过架构手段应对瞬时流量洪峰,保障系统稳定与数据一致。实现原理通常采用分层过滤与异步解耦策略,即在前端、网关、服务层逐级校验与限流,拦截无效请求;利用缓存(如Redis)承载热点数据的极速读操作,并通过消息队列(如RabbitMQ)将同步的瞬时压力转换为异步的平滑处理,最终由数据库确保事务的强一致性。这一架构模式的技术价值在于,它能够以可控的资源成本,显著提升系统的吞吐量和可用性。其典型应用场景便是电商秒杀、限时抢购等业务。本文将以一个基于SpringBoo

weixin_34185512的博客 469

使用idea实现SpringBoot+Mysql+Redis+RabbitMQ+Jmeter的高并发秒杀

使用SpringBoot+Mysql+Redis+RabbitMQ+Jmeter实现高并发秒杀 什么是高并发 高并发(High Concurrency)通常是指通过设计保证系统能够同时并行处理很多请求。通俗来讲,高并发是指在同一个时间点,有很多用户同时的访问同一 API 接口或者 Url 地址。它经常会发生在有大活跃用户量,用户高聚集的业务场景中。 简单分析秒杀 所谓秒杀,就是网络卖家发布一...

baby_Xiao的博客 1054

SpringBoot秒杀项目实战:高并发架构设计与核心问题解决方案

高并发是互联网后端系统设计的核心挑战之一,其本质在于如何高效、安全地处理海量同时请求。其技术原理通常围绕资源争用、数据一致性和系统吞吐量展开,通过缓存、异步、队列等技术手段进行优化。在电商、社交、金融等实时性要求高的应用场景中,高并发处理能力直接决定了系统的稳定性和用户体验。秒杀场景作为高并发技术的典型试金石,集中体现了库存超卖、流量峰值、数据一致性等核心难题。本文以SpringBoot电商秒杀项目为蓝本,深入剖析了利用Redis原子操作进行库存预扣减,并结合消息队列实现流量削峰与异步下单的工程实践方案,为

weixin_34335458的博客 432

Springboot秒杀系统实战:高并发下的防超卖与削峰设计

高并发场景下,瞬时流量集中冲击系统极易引发超卖、数据库连接耗尽和响应延迟等问题,缓存与消息队列成为解决此类问题的关键技术手段。Redis通过原子操作完成库存预减,将无效请求拦截在数据库之前;RabbitMQ则利用异步消息削峰填谷,摊平数据库写入压力;MySQL结合条件更新与唯一索引兜底,确保最终一致性。这种分层架构广泛应用于电商秒杀、限时抢购等业务场景。基于Springboot的电商秒杀系统正是整合了上述组件,形成一套可复现的工程实践方案,其中覆盖了防超卖SQL的写法、用户维度限流、异步下单链路以及压测验证

weixin_31421613的博客 349

Springboot框架集成MySQL、RabbitMQ、Redis、Logback日志、Quartz定时任务

1 创建Springboot项目 网上关于创建Springboot项目的案例有很多,此处就不阐述,提供一个参考案例:使用IDEA创建一个springboot项目 1.1 常用注解 @Mapper 将项目中对应的mapper类的路径加入项目,mybatis使用。 @SpringBootApplication = (默认属性)@Configuration + @EnableAutoConfigura...

麦克劳林 571

基于SpringBoot+Vue的在线考试系统设计与实现

从全栈开发视角出发,SpringBoot以“约定优于配置”简化后端搭建,MySQL依靠事务机制保障成绩数据一致性,Vue的响应式特性则让答题交互更流畅。系统基于JWT实现无状态登录认证,配合随机组卷、自动判分、切屏检测与成绩统计可视化,构建了从题库管理到考试分析的全流程闭环。该方案不仅适合作为毕业设计参考,也适用于快速搭建企业内部培训考核平台。部署环节重点攻克时区配置、跨域处理、history路由刷新404等常见问题,并可通过引入人脸识别或智能组卷算法进一步扩展系统能力,是一套兼具工程实践价值与二次开发空间

weixin_34088583的博客 421

SpringBoot+RabbitMQ+Redis实现秒杀功能

三者都成功后,在redis中存储用户id和订单id,作为秒杀成功的记录,如果用户再次进行秒杀时,直接从redis查询是否存在秒杀成功的记录,存在即返回已经秒杀,不存在就下一步。传统处理:如果不涉及到redis的话,最初的用户请求进来的流程大概是先去数据库判断下当前用户是否已经秒杀过当前商品,如果秒杀过的话则返回秒杀失败不能重复秒杀,否则的话则执行减库存,下订单等步骤。秒杀功能的流程是:获得秒杀资格后,需要进行商品数量减少、生成订单、生成秒杀订单的操作,当三者都成功运行后,才能秒杀成功。

m0_59350665的博客 2590

springboot-seckill:基于SpringBoot + MySQL + Redis + RabbitMQ + Guava开发的高并发商品限时秒杀系统

系统介绍 本系统是使用SpringBoot开发的高并发限时抢购秒杀系统,除了实现基本的登录,查看商品列表,秒杀,下单等功能,项目中还针对高并发情况实现了系统缓存,降级和限流。 开发工具 IntelliJ IDEA + Navicat + Sublime Text3 + Git +Chrome 压测工具 杰米特 开发技术 前端技术:Bootstrap + jQuery + Thymeleaf 初步技术:SpringBoot + MyBatis + MySQL 中间件技术:德鲁伊+雷迪斯+ RabbitMQ +番石榴 秒杀优化方向 将请求阻止拦截在系统上游:传统秒杀系统之所以挂,请求都压倒了串行数据层,数据读写锁冲突严重,几乎所有请求都超时,流量不足大,下单成功的有效流量甚小,我们可以通过限流,降级等措施来最大化减少对数据库的访问,从而保护系统。 充分利用缓存:秒杀商品是一个典型的读多写少的应

亲测可用基于 SpringBoot+Maven+Mybatis+Redis+RabbitMQ 高并发秒杀系统

基于 SpringBoot+Maven+Mybatis+Redis+RabbitMQ 高并发商城秒杀系统; 开发工具IntelliJ IDEA 2017.3.1 x64; 项目搭建: 1、下载代码 将项目加载到IDEA里面 2、运行sql文件夹下的sql文件 3、到src/main/resources下的application.properties下修改你的数据库链接用户名与密码 4、安装redis、mysql、rabbitmq、maven等环境 5、启动前,检查配置 application.properties 中相关redis、mysql、rabbitmq地址 6、登录地址:http://localhost:8080/login/to_login 7、商品秒杀列表地址:http://localhost:8080/goods/to_list

Springboot基于实时消息队列的商城订单秒杀系统g74gz(程序+源码+数据库+调试部署+开发环境)

随着互联网技术的飞速发展,电子商务已成为现代商业活动的重要组成部分。秒杀活动作为电商平台的一种促销手段,能够在短时间内吸引大量用户关注并促进商品销售。然而,传统的秒杀系统在处理高并发请求时,往往面临性能瓶颈,导致用户体验不佳,甚至引发系统崩溃。因此,构建一个高效、稳定的基于实时消息队列的商城订单秒杀系统,对于提升电商平台竞争力和用户满意度具有重要意义。

CK3039的博客 885

cloud-miaosha:基于SpringBoot + MySQL + Redis + RabbitMQ + Guava开发的高并发商品限时秒杀系统

苗沙 基于SpringBoot + MySQL + Redis + RabbitMQ + Guava开发的高并发商品限时秒杀系统

SpringBoot景区票务系统设计与高并发处理实践

分布式系统在现代互联网应用中扮演着关键角色,特别是在高并发场景下的事务处理。SpringBoot作为Java生态的主流框架,通过自动配置和starter依赖大幅降低了分布式应用的开发门槛。本文以景区票务系统为例,详细解析如何利用SpringBoot+MyBatis+Vue技术栈实现日均10万+订单处理能力。重点探讨了Redis预减库存、RabbitMQ异步消峰、Seata分布式事务等核心技术方案,并分享了库存超卖、JWT失效等典型问题的排查过程。对于需要处理高并发交易的电商、票务类系统,这些实践方案具有直接

weixin_32932149的博客 222

springboot+mybatis+shiro+rabbitmq+redis项目实战,自动生成dao,service,controler层代码

1. 用到技术:springboot+mybatis+shiro+rabbitmq+redis项目实战, 2. mybatisplus根据表自动生成dao,service,controler层的增删改成方法,极大提升开发效率 3. 包含功能:登录,用户管理,角色管理,菜单管理。用到插件:插件:lombok,finbugs,p3c等 4. 项目有源代码,有数据库脚本,可快速部署运行

告别传统RAG的痛点!Agent Skills让知识库检索更智能(本地知识库搭建新思路:用Agent Skills实现渐进式检索)

传统RAG在知识库检索中存在文档结构丢失、Token消耗大等问题 📚 Agent Skills通过分层索引、渐进式检索等设计,实现了更智能的本地知识库检索方案 🤖 本文详细介绍了Agent Skills的核心设计理念、与传统RAG的对比以及实践建议,帮助你搭建高效的知识库系统 ✅

XiaoqiangClub的博客 693

Java高并发系统 + 安全监控 完整知识体系

本文系统梳理了Java高并发开发的全方位知识体系,涵盖单机并发基础、分布式架构、系统安全、监控体系和故障治理等核心模块。主要内容包括: 单机并发基础 CPU多级缓存与内存模型 JMM内存模型与happens-before原则 锁机制与CAS原子操作 并发容器与线程池原理 JVM调优与性能优化 分布式高并发架构 分布式锁与一致性算法 缓存体系与典型问题解决方案 消息队列的削峰填谷 负载均衡与分库分表 微服务通信与流量控制 生产级解决方案 高并发业务安全防护 全链路监控体系搭建 典型故障排查与治理 应急预案与性

专注 Java 后端开发,分享基础语法、JVM、并发、Spring 全家桶、微服务、分布式、性能优化等实战干货。坚持输出高质量技术笔记,用简单语言讲清复杂原理,助力每一位 Java 开发者稳步进阶。 575

OpenClaw实战一|企业微信AI客服数字员工:自动应答+工单创建+数据统计,零代码3天落地

OpenClaw做企业微信AI客服数字员工,真正的价值不是“能自动回复”,而是把“咨询-应答-工单-统计-复盘”全流程闭环。对中小企业来说,不用招专职AI开发、不用买昂贵客服系统,一台服务器、零代码配置,就能拥有媲美大厂的智能客服能力。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 517

SpringBoot+Vue租房平台实战:从环境搭建到功能测试全流程解析

这次我们来看一个基于SpringBoot的租房平台项目。这个项目是一个开源的、前后端分离的在线房屋租售管理系统,核心目标是帮助开发者快速搭建一个功能完整的租房业务平台。对于正在学习SpringBoot、Vue,或者需要完成毕业设计、课程设计、个人项目的同学来说,这是一个非常值得参考的实战案例。 项目最核心的几个特点:第一,功能模块齐全,覆盖了从房源管理、用户管理到消息通知、缴费记录等租房业务全流程;第二,技术栈主流且清晰,后端采用SpringBoot,前端采用Vue,是当前企业级开发的标准组合;第三,项目结

weixin_30800987的博客 367

ANSYS——“There is at least 1 small equation solver pivot term”问题的解决办法

ANSYS——“There is at least 1 small equation solver pivot term”问题的解决办法

python_AI_fans的博客 1万+

华为OD机试双机位C卷-分披萨 (Py/Java/C/C++/Js/Go)

华为OD机试(机考)双机位C卷 【分披萨】,提供C语言、Java、C++、Python、Go、JavaScript源码实现,并提供完整思路讲解,以及在线OJ模拟做题。华为od机试 - 分披萨。

qq_45776114的博客 1397

SpringBoot房产租赁管理系统设计与实现源码解析

SpringBoot作为当前主流的Java开发框架,通过自动配置和约定优于配置的设计,极大简化了企业级应用的搭建与部署。其与MyBatis-Plus持久层框架结合,可快速实现单表CRUD、条件查询和分页操作,是中小型管理系统开发的常见技术组合。在房产租赁管理系统中,业务模型涵盖房源、租客、合同、租金账单等核心数据,通过合理设计数据库表结构,利用状态字段实现房源与合同的联动流转,并通过拦截器与BCrypt实现登录认证和密码安全。该方案覆盖从表结构拆分、核心代码实现到定时任务和事务控制等关键技术点,同时提供部署

weixin_33423874的博客 333

YOLO26-Quantized:面向国产AI芯片的全栈量化方案,适配昇腾310P与寒武纪MLU270

在算力国产化替代的行业趋势下,昇腾310P、寒武纪MLU270已成为工业边缘视觉、智能检测场景的主流国产AI芯片选型。针对原生YOLO26模型在国产芯片上推理效率低、算子兼容性差、量化精度塌陷三大核心痛点,本文提出YOLO26-Quantized全栈量化方案,覆盖训练感知量化(QAT)、离线静态量化(PTQ)、模型编译优化、芯片专属部署全流程。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 764
上一篇: RabbitMQ基础入门--SpringBoot + RabbitMQ 实现延时队列
下一篇: Spring Redis Data的基本使用 入门必备!!
iT-放雾矛木_
博客等级 码龄7年 15粉丝 5原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值