Spring Boot Redis 秒杀实现

简述

本文主要通过一个简单的例子模拟实现秒杀情景,其中主要使用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

您有任何想法欢迎评论区留言讨论,谢谢
 

原创文章,作者:1402239773,如若转载,请注明出处:https://blog.ytso.com/243624.html

(0)
上一篇 2022年4月11日
下一篇 2022年4月11日

相关推荐

发表回复

登录后才能评论