Spring Boot Redis 秒杀实现

编程教程 > Java > Spring (4138) 2024-11-26 14:39:04

简述

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

import com.xqlee.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


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

评论
User Image
提示:请评论与当前内容相关的回复,广告、推广或无关内容将被删除。

相关文章
简述本文主要通过一个简单的例子模拟实现秒杀情景,其中主要使用Redis事物进行实现spring boot为提供方便的环境
前言继续上一篇Spring Boot Redis 秒杀实现 的一个修改版本,主要实现用ab工具进行网页正式访问的一个版本,其主要目的还是介绍Redis实现秒杀活动的一种方式
Spring Boot 2.0 Redis整合,通过spring boot 2.0整合Redis作为spring缓存框架的实现。
spring boot 1.5整合redis实现spring的缓存框架,spring boot,redis
redis 命令查看使用情况redis info命令详解,redis查看内存使用情况。redis info命令的详细解释
spring data redis设置缓存的过期时间,spring data redis更新缓存的过期时间
目标使用Redis Stack中间件作为向量数据库(Vector Database)实现文档数据的存储和查询功能。先决条件已安装好的 redis stack ,
Redis 删除/清除数据​​​​​​​1.访问redis根目录    cd  /usr/local/redis-2.8.192.登录redis:redis-cli -h 127.0.0.1 -...
Redis 禁用持久化配置
前置条件Docker 环境开始安装redis-stack打开docker官方hub的地址 redis/redis-stack Tags | Docker Hub
一、spring boot shiro 无状态token认证项目结构图​二、无状态spring boot shiro相关配置2.1shiro redis 缓存配置首先是实现shiro的cache...
Java连接redis启动报错Error redis clients jedis HostAndPort cant resolve localhost address
今天遇到Redis “MISCONF Redis is configured to save RDB snapshots, but is currently not able to persis...
redis在window系统上的下载安装使用说明
Docker安装部署Redisdocker 安装部署Redis环境Linux系统dockerdocker-compose 相关文章:Ubuntu 在线安装 Docker-xqlee (blog....