Redis解决秒杀微服务抢购超卖和同一个用户多次抢购问题

本文介绍了一个基于Java的秒杀系统实现方案,通过使用Hutool和Guava等工具包简化了开发过程。系统利用Redis作为缓存来提高性能并确保数据一致性,采用互斥锁机制防止超卖现象发生。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.导入需要的包

<!-- hutool -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
        </dependency>
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>25.1-jre</version>
        </dependency>

2.代码段


import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import com.feifan.common.core.domain.R;
import com.feifan.common.redis.service.RedisService;
import com.feifan.educate.service.apiService.IEducateQuestionService;
import com.google.common.collect.Interner;
import com.google.common.collect.Interners;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;

@RestController
@RequestMapping("test")
public class TestJMeterController {

    //需要使用key作为互斥锁,所以使用Interners将key添加到常量池中,谷歌包下的
    static final Interner<String> pool = Interners.newWeakInterner();
    @Resource
    private IEducateQuestionService questionService;

    @Resource
    private RedisService redisService; //封装的redis工具
    @GetMapping("jmeterTest")
    public R jmeterTest(@RequestParam Integer userId){
        String now = DateUtil.now();
        //将key作为互斥锁
        synchronized (pool.intern("jmeter" + userId)){
            //从redis中查询用户是否已经抢购成功,如果从数据库中查询会执行的很慢
            if (null != redisService.getCacheObject("jorder:userId"+userId) ){
                return R.fail("您已强够成功不能再次抢购");
            }
            String result = "";
            Integer count = Integer.parseInt(redisService.getCacheObject("jmeter").toString());//查询剩余库存
            System.out.println("剩余库存:"+count);
            if (count > 0){ // 库存大于0,可以抢购
                result =  "抢购成功:"+count;
                System.out.println("用户:"+userId+":抢购成功");
                redisService.setCacheObject("jmeter",count-1);//减库存
                Integer inventory = Integer.parseInt(redisService.getCacheObject("inventory").toString()); //查询已抢购的数量
                redisService.setCacheObject("inventory",inventory+1); //抢购数量+1
                redisService.setCacheObject("jorder:userId"+userId,count);//保存用户抢购成功数据到redis
                questionService.addOrder(userId, IdUtil.simpleUUID()); //保存用户下单数据到数据库
            }else {
                result =  "抢购失败";
            }
            return R.ok(result);
        }
    }


}

3.这里我使用的是jmeter压力测试,同一个用户只能下单一次

 4.redis中的库存初始数据设置为10,已购买数量为0

5. 开始测试

 用同一个用户执行了一万次后我们的redis库存变成了9,已购买数量为1,而数据库中也只有一个用户的购买信息,仍然是只有一单

库存变成了9

已购买数量为1

 用户信息redis中,userId为10的用户有了抢购记录

 mysql数据库中用户数据,userid为10也有一条记录

 这样就实现了秒杀的功能,没有出现超卖,也实现了一个用户只能够抢购一次的功能

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值