Spring Boot Redis 秒杀实现

教程分享 > Java教程 > Spring (4493) 2024-08-07 11:05:25

简述

本文主要通过一个简单的例子模拟实现秒杀情景,其中主要使用Redis事物进行实现spring boot为提供方便的环境。

首先导入redis依赖

pom.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.leftso.demo</groupId>
    <artifactId>demo-redis-seckill</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo-redis-seckill</name>
    <description>Redis 实现产品秒杀</description>

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

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.0.1</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

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

</project>

Redispool配置

配置redis的连接池,这个根据自己需求改。这里测试用。

package com.leftso.demo.demoredisseckill;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

@Configuration
public class JedisConfig {

    @Bean
    public JedisPool jedisPool(){
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        // 设置配置
        jedisPoolConfig.setMaxTotal(1024);
        jedisPoolConfig.setMaxIdle(100);
        jedisPoolConfig.setMaxWaitMillis(100);
        jedisPoolConfig.setTestOnBorrow(false);//jedis 第一次启动时,会报错
        jedisPoolConfig.setTestOnReturn(true);
        JedisPool pool=new JedisPool(jedisPoolConfig,"127.0.0.1",6379);
        return pool;
    }
}

写一个秒杀的业务处理实现

package com.leftso.demo.demoredisseckill.service;


import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Transaction;

import java.util.List;

public class Seckill implements Runnable {
    private JedisPool jedisPool;
    private String userName;
    private String productKey;

    public Seckill(JedisPool jedisPool, String userName, String productKey) {
        this.jedisPool = jedisPool;
        this.userName = userName;
        this.productKey = productKey;
    }


    @Override
    public void run() {
        Jedis jedis=jedisPool.getResource();
        try {
            jedis.watch(productKey);
            String val=jedis.get(productKey);
            int valInt=Integer.valueOf(val);
            if (valInt>=1){
                Transaction tx=jedis.multi();
                tx.incrBy(productKey,-1);//原子操作
                List<Object> list=tx.exec();
                if (list==null||list.isEmpty()){
                    System.out.println("用户:"+userName+" 抢购失败。");
                    this.run();//再抢
                }else{
                    System.out.println("用户:"+userName+ " 抢购成功!!!");
//                    jedis.setnx(productKey,)
                    jedis.rpush(productKey+"user",userName);//成功用户添加入队列
                }
            }else{
                System.out.println("商品已抢购完毕-------");
            }

        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

最后模拟访问

package com.leftso.demo.demoredisseckill;

import com.leftso.demo.demoredisseckill.service.Seckill;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import redis.clients.jedis.JedisPool;

import java.util.ArrayList;
import java.util.List;

@RunWith(SpringRunner.class)
@SpringBootTest
public class RedisSeckillTest {
    private final static Logger logger = LoggerFactory.getLogger(RedisSeckillTest.class);

    @Autowired
    JedisPool jedisPool;

    String productKey="SSSSSSKEY";
    int productNum=10;

    @Before
    public void before(){
        jedisPool.getResource().set(productKey,10+"");//设置产品默认库存数量
        while (jedisPool.getResource().lpop(productKey+"user")!=null){

        }//清空秒杀成功人用户列表
        //end
    }

    @After
    public void after(){
        String num=jedisPool.getResource().get(productKey);
        System.out.println("剩余库存:"+num);
    }

    @Test
    public void contextLoads() {
        try {
            for (int i = 0; i < 100; i++) {
                //每个用户件数
                Thread t = new Thread(new Seckill(jedisPool,"用户"+i,productKey));
                t.start();
            }

            long size=jedisPool.getResource().llen(productKey+"user");
            while (true){
                if (size==productNum){
                    break;
                }else{
                    size=jedisPool.getResource().llen(productKey+"user");
                }
            }
            List<String> successUsers=new ArrayList<>();
            String  user=jedisPool.getResource().lpop(productKey+"user");
            while (user!=null){
                successUsers.add(user);
                user=jedisPool.getResource().lpop(productKey+"user");
            }


            System.out.println("活动结束>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>活动结束");
            System.out.println("获奖名单:"+successUsers);
            Thread.currentThread().sleep(2000);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

执行单元测试,查看结果:
..............................
商品已抢购完毕-------
商品已抢购完毕-------
商品已抢购完毕-------
商品已抢购完毕-------
商品已抢购完毕-------
商品已抢购完毕-------
商品已抢购完毕-------
商品已抢购完毕-------
商品已抢购完毕-------
商品已抢购完毕-------
商品已抢购完毕-------
商品已抢购完毕-------
商品已抢购完毕-------
商品已抢购完毕-------
商品已抢购完毕-------
商品已抢购完毕-------
活动结束>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>活动结束
获奖名单:[用户66, 用户2, 用户8, 用户10, 用户56, 用户78, 用户33, 用户58, 用户16, 用户87]
剩余库存:0

Process finished with exit code 0


您有任何想法欢迎评论区留言讨论,谢谢
 
https://www.leftso.com/article/615.html

相关文章
简述本文主要通过一个简单的例子模拟实现秒杀情景,其中主要使用Redis事物进行实现spring boot为提供方便的环境
前言继续上一篇Spring Boot Redis 秒杀实现 的一个修改版本,主要实现用ab工具进行网页正式访问的一个版本,其主要目的还是介绍Redis实现秒杀活动的一种方式
spring boot 1.5整合redis实现spring的缓存框架,spring boot,redis
Spring Boot 2.0 Redis整合,通过spring boot 2.0整合Redis作为spring缓存框架的实现。
spring data redis设置缓存的过期时间,spring data redis更新缓存的过期时间
Java编程之spring boot shiro redis整合基于角色和权限的安全管理,Java编程,spring boot,shiro,权限控制
spring boot 入门之整合spring session实现session共享。一直以来Java编程中web项目中的session共享问题都是一个很难解决的问题。接下来将讲解通过sprin...
一、spring boot shiro 无状态token认证项目结构图​二、无状态spring boot shiro相关配置2.1shiro redis 缓存配置首先是实现shiro的cache...
思路通过redis的有效期和切面来配合处理环境springboot2.7.xspring-boot-starter-webspring-boot-starter-aopjava1.8redis编...
spring boot RedisTemplateHelper import org.springframework.context.annotation.Bean; import org.s...
spring boot 入门之spring session实现restful apis。通过spring boot或者spring mvc整合spring session的方式来实现sessio...
spring boot 2.x设置静态资源缓存时间
spring boot又一个spring框架的经典项目,本文讲解spring boot入门的环境配置以及第一个项目,Spring Boot 入门教程
Spring Boot 2.0 入门 logoback配置实战教程,俗话说好马配好鞍。Spring Boot 框架从各方面给我们带来了开发效率。日志自然也不会落下。本文将讲解与Spring Bo...
Spring Boot MQTT协议通过spring boot整合apache artemis实现Java语言MQTT协议通信,搭建MQTT服务器可以参考上一篇 MQTT Java入门-搭建MQ...