目录
- 1、构建springboot项目
- 2、启动类
- 3、在controller层里定义秒杀接口
- 4、在service层里通过lua脚本实现秒杀效果
- 5、配置redis连接参数
- 6、演示秒杀效果
- 6.1 准备redis环境
- 6.2 启动项目
- 6.3 多线程形式发起秒杀请求
1、构建springboot项目
搭建名为quickbuy的springboot项目,相关的依赖包如下所示:
<?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 https://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.13.release</version>
<relativepath/> <!-- lookup parent from repository -->
</parent>
<groupid>com.baizhi</groupid>
<artifactid>quickbuy</artifactid>
<version>0.0.1-snapshot</version>
<name>quickbuy</name>
<description>demo project for spring boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-data-redis</artifactid>
</dependency>
<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>
</dependency>
<dependency>
<groupid>org.apache.httpcomponents</groupid>
<artifactid>httpclient</artifactid>
<version>4.5.5</version>
</dependency>
<dependency>
<groupid>org.apache.httpcomponents</groupid>
<artifactid>httpcore</artifactid>
<version>4.4.10</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-maven-plugin</artifactid>
</plugin>
</plugins>
</build>
</project>
引入了redis、httpclient等依赖包。
项目结构
2、启动类
package com.baizhi;
import org.springframework.boot.springapplication;
import org.springframework.boot.autoconfigure.springbootapplication;
@springbootapplication
public class quickbuyapplication {
public static void main(string[] args) {
springapplication.run(quickbuyapplication.class, args);
}
}
3、在controller层里定义秒杀接口
@restcontroller
public 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;
@service
public 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<string> redisscript=new defaultredisscript<string>();
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=8081 spring.redis.host=192.168.159.22 spring.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的秒杀案例的文章就介绍到这了,更多相关redis结合springboot秒杀内容请搜索www.887551.com以前的文章或继续浏览下面的相关文章希望大家以后多多支持www.887551.com!