栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

redis(四) - springboot + redis实现商品秒杀

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

redis(四) - springboot + redis实现商品秒杀

1、index.html



    
    Title
    
    


    
    


2、Controller
@RestController
@RequestMapping("/test")
public class SecKillController {

    @Autowired
    SecKillService secKillService;

    @RequestMapping("/secKill")
    public boolean secKill(String prodId){
        if (prodId == null || "".equals(prodId)){
            return false;
        }
        Random random = new Random();
        int uid = random.nextInt(50000);
        return secKillService.secKillByscript(prodId,String.valueOf(uid));
    }
}

3、Service
@Service
public class SecKillService {

    @Autowired
    RedisTemplate redisTemplate;

    public boolean secKillByscript(String proId,String uId){

        if ("".equals(proId) || null == proId ||"".equals(uId) || null == uId){
            return false;
        }

        DefaultRedisscript redisscript = new DefaultRedisscript();
        //加载字符串格式脚本
//        redisscript.setscriptText();
        //加载文本格式脚本
        redisscript.setLocation(new ClassPathResource("secKill.lua"));
        redisscript.setResultType(String.class);
        List list = new ArrayList<>();
        list.add(uId);
        list.add(proId);
        Object execute = redisTemplate.execute(redisscript, new StringRedisSerializer(),
                new StringRedisSerializer(), list, uId, proId);

        if ("0".equals(String.valueOf(execute))){
            System.out.println("未开始");
        }else if("1".equals(String.valueOf(execute))){
            System.out.println("已抢光");
        }else if("2".equals(String.valueOf(execute))){
            System.out.println("已秒杀");
        }else if("3".equals(String.valueOf(execute))){
            System.out.println("秒杀成功");
        }
        return true;
    }
}
4、lua 脚本
  • 在lua脚本中,有两个全局的变量,是用来接收redis应用端传递的键值和其它参数的,分别为KEYS、ARGV。

  • 在应用端传递给KEYS时是一个数组列表,在lua脚本中通过索引方式获取数组内的值。

  • 在应用端,传递给ARGV的参数比较灵活,可以是多个独立的参数,但对应到Lua脚本中是,统一用ARGV这个数组接收,获取方式也是通过数组下标获取

redisTemplate.execute(redisscript, new StringRedisSerializer(),
                new StringRedisSerializer(), list, uId, proId);

就拿 SecKillService 中的举例,参数列表中的 list就是有 KEYS 接收;而后面的参数( uId、proId )由 ARGV 接收

secKill.lua

-- KEYS[1] =list(0) 
local userid=KEYS[1];
-- KEYS[2] =list(1) 
local prodid=KEYS[2];
local uidKey="prod:user:"..userid;
local proKey="prod:kc:"..prodid;
--redis.log(redis.LOG_NOTICE,uidKey);
--判断是否有库存,没有表示未开启秒杀
local userExists=redis.call("exists",proKey);
if tonumber(userExists)==0 then
    return "0";
end
--判断库存是否足够,不够停止秒杀
local num=redis.call("get",proKey);
--redis.log(redis.LOG_NOTICE,proKey);
if tonumber(num) <=0 then
    return "1";
end
--判断用户是否已参与过秒杀活动
local isMember=redis.call("sisMember",uidKey,userid);
if tonumber(isMember)==1 then
    return "2";
else
    redis.call("decr",proKey);
    redis.call("sadd",uidKey,userid);
end
return "3";
5、配置文件

application.properties

server.port=8001
#redis配置
spring.redis.host=xxx.xxx.xxx.xx
spring.redis.port=6379
spring.redis.password=redis123
spring.redis.database=0
spring.redis.timeout=1800000
spring.redis.lettuce.pool.max-active=20
spring.redis.lettuce.pool.max-wait=1
spring.redis.lettuce.pool.max-idle=50
spring.redis.lettuce.pool.min-idle=0
6、依赖

pom.xml

 

	org.springframework.boot
	spring-boot-starter-data-redis
	2.5.6




	org.apache.commons
	commons-pool2



	org.springframework.boot
	spring-boot-starter-thymeleaf
	2.5.6

        


	org.webjars
	jquery
	3.6.0

7、测试

通过 linux 中的 ab 测试接口

ab -n 2000 -c 200 -p ~/postfile -T application/x-www-form-urlencoded http://192.168.43.99:8001/test/secKill	
  • -n :总访问次数
  • -c :每次的并发量
  • -p :保存参数的文件
  • -T :请求类型

postfile

prodId=0001&

或者

ab -n 2000 -c 200 -T application/x-www-form-urlencoded http://192.168.43.99:8001/test/secKill?prodId=0001
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/572909.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号