千家信息网

如何基于Redis结合SpringBoot实现秒杀

发表于:2024-10-01 作者:千家信息网编辑
千家信息网最后更新 2024年10月01日,这篇文章主要介绍如何基于Redis结合SpringBoot实现秒杀,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!1、构建SpringBoot项目搭建名为quickbuy的spr
千家信息网最后更新 2024年10月01日如何基于Redis结合SpringBoot实现秒杀

这篇文章主要介绍如何基于Redis结合SpringBoot实现秒杀,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!

1、构建SpringBoot项目

搭建名为quickbuy的springboot项目,相关的依赖包如下所示:

    4.0.0            org.springframework.boot        spring-boot-starter-parent        2.1.13.RELEASE                 com.baizhi    quickbuy    0.0.1-SNAPSHOT    quickbuy    Demo project for Spring Boot            1.8                            org.springframework.boot            spring-boot-starter-data-redis                            org.springframework.boot            spring-boot-starter-web                            org.springframework.boot            spring-boot-starter-test            test                            org.apache.httpcomponents            httpclient            4.5.5                            org.apache.httpcomponents            httpcore            4.4.10                                                    org.springframework.boot                spring-boot-maven-plugin                        

引入了Redis、HttpClient等依赖包。
项目结构

2、启动类

package com.baizhi;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublic class QuickbuyApplication {    public static void main(String[] args) {        SpringApplication.run(QuickbuyApplication.class, args);    }}

3、在Controller层里定义秒杀接口

@RestControllerpublic class QuickBuyController {    @Autowired    private SellService sellService;    @RequestMapping("/quickBuy/{item}/{owner}")    public String quickbuy(@PathVariable String item,@PathVariable String owner){        String result=sellService.quickBuy(item,owner);        if(!result.equals("0")){            return owner+"success";        }else{            return owner+"fail";        }    }}

  通过@RequestMapping注解们可以把"/quickBuy/{item}/{owner}"格式的url映射到quickBuy方法上。
   quickBuy是秒杀接口,该接口包含的两个参数是item和owner,分别表示待秒杀的商品名和发起秒杀请求的用户。这两个参数均被@PathVariable注解修饰,说明来自于url里的{item}和{owner}部分。
  在这个quickBuy秒杀接口中调用了SellService类里的quickBuy方法实现了秒杀功能,并根据SellService类quickBuy方法返回的结果,向外部返回"秒杀成功"或"秒杀失败"的字符串语句。

4、在Service层里通过lua脚本实现秒杀效果

package com.baizhi.service;import org.springframework.data.redis.connection.RedisConnection;import org.springframework.data.redis.connection.ReturnType;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.data.redis.core.script.DefaultRedisScript;import org.springframework.stereotype.Service;import javax.annotation.Resource;@Servicepublic class SellService {    @Resource    private RedisTemplate redisTemplate;    public String quickBuy(String item, String owner) {        //用lua脚本实现秒杀        String luaScript="local owner=ARGV[1]\n" +                "local item=KEYS[1] \n" +                "local leftNum=tonumber(redis.call('get',item)) \n" +                "if(leftNum>=1)\n" +                "then redis.call('decrby',item,1)\n" +                "redis.call('rpush','ownerList',owner)\n" +                "return 1 \n" +                "else \n" +                "return 0 \n" +                "end\n" +                "\n";        String key=item;        String args=owner;        DefaultRedisScript redisScript=new DefaultRedisScript();        redisScript.setScriptText(luaScript);        //调用lua脚本,请注意传入的参数        Object luaResult=redisTemplate.execute((RedisConnection connection)->connection.eval(           redisScript.getScriptAsString().getBytes(),           ReturnType.INTEGER,           1,           key.getBytes(),           args.getBytes()        ));        //根据lua脚本的执行情况返回结果        return luaResult.toString();    }}

对lua脚本的解释如下:

   通过ARGV[1]参数传入发起秒杀请求的用户,用KEYS[1]参数传入待秒杀的商品。通过get item命令判断item商品在Redis里还有多少库存。
  if语句中判定剩余库存大于等于1,就会先执行decrby命令把库存数减1,随后调用第6行的rpush命令,在ownerList里记录当前秒杀成功的用户,并通过return 1表示秒杀成功。如果判断库存数已经小于1,那么return 0表示秒杀失败。
  其中将lua脚本赋予redisScript对象,并通过redisTemplate.execute方法执行lua脚本。

在调用redisTemplate.execute方法执行lua脚本时请注意以下三点:

  • 需要以butes方式传入脚本

  • 需要指定返回类型

  • 传入该lua脚本所包含的KEYS类型参数的个数是1.

  • 传入的KEYS和ARGV类型的参数需要转换成bytes类型

5、配置redis连接参数

application.properties

server.port=8081spring.redis.host=192.168.159.22spring.redis.port=6379

6、演示秒杀效果

6.1 准备redis环境

我用的刚搭建的redis主从复制集群,一主二从

设置10个商品

6.2 启动项目

  在浏览器访问http://localhost:8081/quickBuy/Computer/abc,测试秒杀接口,该url传入的商品名是"Computer",需要和上面设置的商品名称一致,传入的发起秒杀请求的客户端名字为abc。输入该url后,能看到表示秒杀成功的如下输出。


进入redis查看


发现商品数量变成了9,且能看到秒杀成功的用户列表。

6.3 多线程形式发起秒杀请求

QuickBuyClients.java

package com.baizhi.client;import org.apache.http.HttpEntity;import org.apache.http.client.ClientProtocolException;import org.apache.http.client.methods.CloseableHttpResponse;import org.apache.http.client.methods.HttpGet;import org.apache.http.impl.client.CloseableHttpClient;import org.apache.http.impl.client.HttpClientBuilder;import org.apache.http.util.EntityUtils;public class QuickBuyClients extends Thread{    @Override    public void run() {        QuickBuyUtil.quickBuy();    }    public static void main(String[] args) {        //开启15个线程,线程数多余秒杀商品数        for(int cnt=0;cnt<15;cnt++){            new QuickBuyClients().start();        }    }}//封装秒杀方法的工具类class QuickBuyUtil{    //在这个方法里,用HttpGet对象发起秒杀请求    public static void quickBuy(){        String user=Thread.currentThread().getName();        CloseableHttpClient httpClient= HttpClientBuilder.create().build();        //创建秒杀Get类型的url请求        HttpGet httpGet=new HttpGet("http://localhost:8081/quickBuy/Computer/"+user);        //得到响应结果        CloseableHttpResponse res=null;        try{            res=httpClient.execute(httpGet);            HttpEntity responseEntity=res.getEntity();            if(res.getStatusLine().equals("200")&&responseEntity!=null){                System.out.println("秒杀结果:"+ EntityUtils.toString(responseEntity));            }        }catch (ClientProtocolException e){            e.printStackTrace();        }catch (Exception e){            e.printStackTrace();        }finally {            try{                //回收http连接资源                if(httpClient!=null){                    httpClient.close();                }                if(res!=null){                    res.close();                }            }catch (Exception e){                e.printStackTrace();            }        }    }}

先重新设置商品数量为10

启动上面的程序
再次进入Redis查看商品数量和秒杀成功的用户

可以看到,15个线程秒杀商品,最终成功的只有10个。

以上是"如何基于Redis结合SpringBoot实现秒杀"这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注行业资讯频道!

0