java redis 實現搶購秒殺


2018.10.24 今天研究了下搶購秒殺的功能實現

網上查了一大堆 用redis的最多。

主要是通過redis的 watch multi 事務來控制秒殺數量 不超賣。

這里說下自己的感受:

不超賣的話 那就要一個個的來減庫存 這樣的話 效率上會有點問題 這里上下代碼 基本上是再網上抄的 。

我用的是 springboot jedis

我就直接上代碼了 

Controller層

package com.bicon.basedemo.controller;

import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.annotation.Resource;

import org.omg.CORBA.PRIVATE_MEMBER;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;


@RestController
@RequestMapping("/test")
public class test {
    
//    @Resource
//    RedisOperation redisOps;
    
    @Resource
    private JedisPool jedisPool;

    @RequestMapping("/redis")
    public void redisTest() {
        Jedis jedis = jedisPool.getResource();
        final String watchkeys = "watchkeys";
        ExecutorService executor = Executors.newFixedThreadPool(20);  //20個線程池並發數

        jedis.set(watchkeys, "10");//設置起始的搶購數
       // jedis.del("setsucc", "setfail");
        jedis.close();
         
        for (int i = 0; i < 101; i++) {//設置101個人來發起搶購 模擬101個人搶購
            executor.execute(new MyRunnable(jedisPool));
        }
        executor.shutdown();
    }
    
     public static String getRandomString(int length) { //length是隨機字符串長度
         String base = "abcdefghijklmnopqrstuvwxyz0123456789";  
         Random random = new Random();  
         StringBuffer sb = new StringBuffer();  
         for (int i = 0; i < length; i++) {  
             int number = random.nextInt(base.length());  
             sb.append(base.charAt(number));  
         }  
         return sb.toString();  
      } 
}

MyRunnable 代碼
package com.bicon.basedemo.controller;

import java.util.List;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.Transaction;

public class MyRunnable implements Runnable{
    
    
    private JedisPool jedisPool;
    String userinfo;
    String watchkeys = "watchkeys";
    public MyRunnable(JedisPool jedisPoo){
        jedisPool = jedisPoo;
    };
    
    public void run() {
        Jedis jedis = jedisPool.getResource();
        try {
            jedis.watch(watchkeys);// watchkeys
 
            String val = jedis.get(watchkeys);
            int valint = Integer.valueOf(val);
            
            if (valint <= 100 && valint>=1) {
            
                 Transaction tx = jedis.multi();// 開啟事務
               // tx.incr("watchkeys");
                tx.incrBy("watchkeys", -1);
 
                List<Object> list = tx.exec();// 提交事務,如果此時watchkeys被改動了,則返回null
                 
                if (list == null ||list.size()==0) {
                    System.out.println("重新搶購");
                    this.run();
                    return;
                } else {
                    for(Object succ : list){
                         String succuserifo ="succ"+succ.toString() +userinfo ;
                         String succinfo="用戶:" + succuserifo + "搶購成功,當前搶購成功人數:"
                                 + (1-(valint-10));
                         System.out.println(succinfo);
                         /* 搶購成功業務邏輯 */
                         jedis.setnx(succuserifo, succinfo);
                    }
                }
            } else {
                    String failuserifo ="kcfail" +  userinfo;
                    String failinfo1="用戶:" + failuserifo + "商品被搶購完畢,搶購失敗";
                    System.out.println(failinfo1);
                    jedis.setnx(failuserifo, failinfo1);
                    return;
            }
 
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            jedis.close();
        }
    }

}

 

最后是效果

 

這段代碼問題其實還是有的:就是沒有按照順來來搶購 

其實我覺得有種方法。就是將請求 存入 kafka中 

然后取kafka中前面的數據 一直取到搶購的數量(用戶不重復)

這樣不就可以了嗎,不需要考慮超賣問題啥的。純屬自己的感想。

 

后來看了一個用rabbitMQ 做的 搶購

把請求插入rabbitMQ隊列。然后 消費端訂閱數據 來實現搶購。

2018-11-21 今天在github上看到一個秒殺的項目 還不錯 分享給大家

https://github.com/hfbin/Seckill

這個里面有兩個 分支,第二個分支是支持rabbitmq的。我覺得 做的還不完美。不過很有借鑒意義。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM