Redis实现秒杀解决超卖情况

唠嗑:网上瞎逛,看到秒杀活动,就发现自己没有了解过这方面的,就去网上查了实现方法,这里做个记录,顺便自己实现一下。

一、大体思路:提前把要进行秒杀的活动商品存入缓存中,秒杀成功或失败直接返回,秒杀成功,则异步执行下单操作。

二、这里主要是通过Redis事务以及watch防止超卖。
2.1先介绍一下watch机制

Redis Watch 命令用于监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。

【 以下是自己对于Redis事务以及watch防止超卖的理解。】
举个例子:两个线程同时进来了,第一个线程进来开启了事务,然后修改key值,同时第二线程也进来开启了事务,又再次在第一个线程执行事务之前修改了key值,则第一个线程执行事务就会失败,第二会执行成功。
就保证在取得同一个key值得情况下,只有一个线程可以执行成功。

2.2 补充Redis事务机制

用下面这张图补充一下,再开启事务后multi,操作key的命令会放入事务队列,在执行事务exec时,watch(key)发现在事务队列中key被其他命令修改了,则当前事务执行就会失败。


image.png

三、代码

package test;

import cn.huangsong.controller.SecKillDemo;
import org.junit.Test;
import redis.clients.jedis.Jedis;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class SecKillTest {
    //用于保存商品的key
    private static String key = "watch_key";
    private Jedis jedis = new Jedis("127.0.0.1", 6379);
    //创建线程池
    private static ExecutorService executorService = Executors.newFixedThreadPool(8);

    /**
     * 初始化redis库存商品  存入100个商品
     */
    @Test
    public void init(){
        jedis.set(key,String.valueOf(100));
    }

    public static void main(String[] args) {
        try{
            //模拟1000个人抢购商品
            for (int i = 1; i <= 1000; i++) {
                executorService.submit(new SecKillDemo("顾客"+i,key));
            }
        }finally {
            executorService.shutdown();
        }
    }
}
package cn.huangsong.controller;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;

import java.util.List;

public class SecKillDemo implements Runnable {
    private Jedis jedis = new Jedis("127.0.0.1", 6379);
    private String customerName;
    private String key;

    public SecKillDemo(String customerName, String key) {
        this.customerName = customerName;
        this.key = key;
    }

    @Override
    public void run() {
        int currentNum;
       //通过watch监控key是否被其他线程操作。
        jedis.watch(key);
        String data = jedis.get(key);
        currentNum = Integer.parseInt(data);
        if (currentNum > 0) {
            //开启事务
            Transaction transaction = jedis.multi();
            //设置新值,如果key的值被其它连接的客户端修改,那么当前连接的exec命令将执行失败
            currentNum--;
            transaction.set(key, String.valueOf(currentNum));
            //如果key被其他线程修改,则exec命令将执行失败
            List res = transaction.exec();
            if (res.size() == 0) {
                System.out.println(customerName + " 抢购失败");
            } else {
                //mq异步处理下单信息。
                System.out.println(customerName + " 抢购成功,[" + key + "]剩余:" + currentNum);
            }
        } else {
            System.out.println(customerName+"商品售空,活动结束!");
        }
    }
}

四、输出结果

顾客5 抢购成功,[watch_key]剩余:99
顾客3 抢购失败
顾客7 抢购失败
顾客8 抢购失败
顾客2 抢购失败
顾客1 抢购失败
顾客10 抢购成功,[watch_key]剩余:98
顾客6 抢购失败
顾客4 抢购失败
顾客11 抢购成功,[watch_key]剩余:97
顾客12 抢购失败
顾客13 抢购成功,[watch_key]剩余:96
顾客14 抢购失败
顾客9 抢购失败
顾客15 抢购失败
顾客18 抢购成功,[watch_key]剩余:95
顾客17 抢购失败
顾客16 抢购失败
顾客19 抢购失败
顾客20 抢购成功,[watch_key]剩余:94
顾客23 抢购失败
顾客21 抢购失败
顾客22 抢购失败
顾客25 抢购成功,[watch_key]剩余:93
顾客24 抢购失败
顾客26 抢购失败
顾客27 抢购成功,[watch_key]剩余:92
顾客28 抢购失败
顾客30 抢购失败
顾客29 抢购失败
顾客31 抢购失败
顾客32 抢购成功,[watch_key]剩余:91
顾客33 抢购失败
顾客34 抢购失败
顾客35 抢购成功,[watch_key]剩余:90
顾客36 抢购失败
顾客37 抢购失败
顾客38 抢购失败
顾客39 抢购成功,[watch_key]剩余:89
顾客41 抢购失败
顾客40 抢购失败
顾客42 抢购成功,[watch_key]剩余:88
顾客43 抢购失败
顾客45 抢购成功,[watch_key]剩余:87
顾客44 抢购失败
顾客47 抢购失败
顾客46 抢购失败
顾客49 抢购成功,[watch_key]剩余:86
顾客48 抢购失败
顾客50 抢购失败
顾客51 抢购成功,[watch_key]剩余:85
顾客53 抢购失败
顾客52 抢购失败
顾客54 抢购成功,[watch_key]剩余:84
顾客56 抢购失败
顾客57 抢购失败
顾客55 抢购失败
顾客58 抢购成功,[watch_key]剩余:83
顾客59 抢购失败
顾客60 抢购失败
顾客61 抢购成功,[watch_key]剩余:82
顾客63 抢购失败
顾客65 抢购失败
顾客62 抢购失败
顾客64 抢购失败
顾客66 抢购成功,[watch_key]剩余:81
顾客67 抢购失败
顾客68 抢购失败
顾客69 抢购成功,[watch_key]剩余:80
顾客70 抢购失败
顾客71 抢购失败
顾客72 抢购失败
顾客73 抢购成功,[watch_key]剩余:79
顾客74 抢购失败
顾客75 抢购失败
顾客76 抢购成功,[watch_key]剩余:78
顾客77 抢购失败
顾客78 抢购失败
顾客79 抢购失败
顾客80 抢购成功,[watch_key]剩余:77
顾客81 抢购失败
顾客83 抢购成功,[watch_key]剩余:76
顾客84 抢购失败
顾客82 抢购失败
顾客85 抢购失败
顾客86 抢购成功,[watch_key]剩余:75
顾客87 抢购失败
顾客88 抢购失败
顾客89 抢购成功,[watch_key]剩余:74
顾客90 抢购失败
顾客91 抢购失败
顾客92 抢购失败
顾客93 抢购成功,[watch_key]剩余:73
顾客94 抢购失败
顾客96 抢购失败
顾客95 抢购失败
顾客97 抢购成功,[watch_key]剩余:72
顾客98 抢购失败
顾客99 抢购失败
顾客100 抢购成功,[watch_key]剩余:71
顾客102 抢购失败
顾客103 抢购成功,[watch_key]剩余:70
顾客101 抢购失败
顾客104 抢购失败
顾客105 抢购失败
顾客106 抢购成功,[watch_key]剩余:69
顾客107 抢购失败
顾客109 抢购成功,[watch_key]剩余:68
顾客111 抢购失败
顾客108 抢购失败
顾客110 抢购失败
顾客112 抢购成功,[watch_key]剩余:67
顾客113 抢购失败
顾客114 抢购失败
顾客115 抢购成功,[watch_key]剩余:66
顾客116 抢购失败
顾客117 抢购失败
顾客119 抢购成功,[watch_key]剩余:65
顾客118 抢购失败
顾客120 抢购失败
顾客121 抢购失败
顾客122 抢购成功,[watch_key]剩余:64
顾客123 抢购失败
顾客124 抢购失败
顾客125 抢购成功,[watch_key]剩余:63
顾客128 抢购成功,[watch_key]剩余:62
顾客126 抢购失败
顾客127 抢购失败
顾客129 抢购失败
顾客130 抢购失败
顾客131 抢购成功,[watch_key]剩余:61
顾客132 抢购失败
顾客133 抢购失败
顾客134 抢购成功,[watch_key]剩余:60
顾客135 抢购失败
顾客137 抢购成功,[watch_key]剩余:59
顾客138 抢购失败
顾客136 抢购失败
顾客139 抢购失败
顾客140 抢购成功,[watch_key]剩余:58
顾客141 抢购失败
顾客142 抢购失败
顾客143 抢购成功,[watch_key]剩余:57
顾客144 抢购失败
顾客145 抢购失败
顾客146 抢购成功,[watch_key]剩余:56
顾客147 抢购失败
顾客148 抢购失败
顾客149 抢购成功,[watch_key]剩余:55
顾客151 抢购失败
顾客152 抢购成功,[watch_key]剩余:54
顾客150 抢购失败
顾客154 抢购失败
顾客153 抢购失败
顾客155 抢购成功,[watch_key]剩余:53
顾客156 抢购失败
顾客157 抢购失败
顾客158 抢购失败
顾客160 抢购成功,[watch_key]剩余:52
顾客159 抢购失败
顾客161 抢购失败
顾客162 抢购成功,[watch_key]剩余:51
顾客163 抢购失败
顾客165 抢购失败
顾客166 抢购成功,[watch_key]剩余:50
顾客164 抢购失败
顾客167 抢购失败
顾客168 抢购失败
顾客169 抢购成功,[watch_key]剩余:49
顾客171 抢购失败
顾客170 抢购失败
顾客173 抢购失败
顾客172 抢购成功,[watch_key]剩余:48
顾客174 抢购失败
顾客175 抢购失败
顾客176 抢购失败
顾客177 抢购成功,[watch_key]剩余:47
顾客179 抢购失败
顾客178 抢购失败
顾客180 抢购成功,[watch_key]剩余:46
顾客182 抢购失败
顾客181 抢购失败
顾客183 抢购失败
顾客184 抢购成功,[watch_key]剩余:45
顾客185 抢购失败
顾客186 抢购失败
顾客188 抢购成功,[watch_key]剩余:44
顾客187 抢购失败
顾客189 抢购失败
顾客190 抢购失败
顾客191 抢购成功,[watch_key]剩余:43
顾客192 抢购失败
顾客193 抢购失败
顾客194 抢购成功,[watch_key]剩余:42
顾客195 抢购失败
顾客196 抢购失败
顾客197 抢购成功,[watch_key]剩余:41
顾客198 抢购失败
顾客199 抢购失败
顾客200 抢购成功,[watch_key]剩余:40
顾客201 抢购失败
顾客202 抢购失败
顾客203 抢购成功,[watch_key]剩余:39
顾客204 抢购失败
顾客205 抢购失败
顾客207 抢购成功,[watch_key]剩余:38
顾客208 抢购失败
顾客206 抢购失败
顾客209 抢购失败
顾客210 抢购成功,[watch_key]剩余:37
顾客211 抢购失败
顾客212 抢购失败
顾客213 抢购成功,[watch_key]剩余:36
顾客214 抢购失败
顾客215 抢购失败
顾客216 抢购成功,[watch_key]剩余:35
顾客217 抢购失败
顾客218 抢购失败
顾客219 抢购成功,[watch_key]剩余:34
顾客220 抢购失败
顾客221 抢购失败
顾客222 抢购成功,[watch_key]剩余:33
顾客223 抢购失败
顾客225 抢购成功,[watch_key]剩余:32
顾客226 抢购失败
顾客224 抢购失败
顾客228 抢购成功,[watch_key]剩余:31
顾客229 抢购失败
顾客227 抢购失败
顾客231 抢购成功,[watch_key]剩余:30
顾客232 抢购失败
顾客230 抢购失败
顾客234 抢购失败
顾客233 抢购成功,[watch_key]剩余:29
顾客237 抢购失败
顾客236 抢购成功,[watch_key]剩余:28
顾客235 抢购失败
顾客238 抢购失败
顾客239 抢购失败
顾客241 抢购成功,[watch_key]剩余:27
顾客240 抢购失败
顾客242 抢购失败
顾客244 抢购成功,[watch_key]剩余:26
顾客245 抢购失败
顾客243 抢购失败
顾客247 抢购成功,[watch_key]剩余:25
顾客248 抢购失败
顾客246 抢购失败
顾客249 抢购失败
顾客250 抢购成功,[watch_key]剩余:24
顾客251 抢购失败
顾客252 抢购失败
顾客254 抢购成功,[watch_key]剩余:23
顾客253 抢购失败
顾客255 抢购失败
顾客256 抢购失败
顾客257 抢购成功,[watch_key]剩余:22
顾客259 抢购失败
顾客260 抢购成功,[watch_key]剩余:21
顾客258 抢购失败
顾客261 抢购失败
顾客262 抢购失败
顾客263 抢购成功,[watch_key]剩余:20
顾客264 抢购失败
顾客266 抢购失败
顾客265 抢购失败
顾客267 抢购成功,[watch_key]剩余:19
顾客268 抢购失败
顾客270 抢购成功,[watch_key]剩余:18
顾客271 抢购失败
顾客269 抢购失败
顾客272 抢购失败
顾客273 抢购成功,[watch_key]剩余:17
顾客274 抢购失败
顾客275 抢购失败
顾客276 抢购成功,[watch_key]剩余:16
顾客278 抢购失败
顾客279 抢购成功,[watch_key]剩余:15
顾客277 抢购失败
顾客280 抢购失败
顾客281 抢购失败
顾客282 抢购成功,[watch_key]剩余:14
顾客284 抢购失败
顾客285 抢购成功,[watch_key]剩余:13
顾客283 抢购失败
顾客286 抢购失败
顾客287 抢购失败
顾客288 抢购失败
顾客289 抢购成功,[watch_key]剩余:12
顾客290 抢购失败
顾客291 抢购失败
顾客292 抢购成功,[watch_key]剩余:11
顾客293 抢购失败
顾客294 抢购失败
顾客295 抢购成功,[watch_key]剩余:10
顾客296 抢购失败
顾客297 抢购失败
顾客298 抢购成功,[watch_key]剩余:9
顾客299 抢购失败
顾客300 抢购失败
顾客301 抢购成功,[watch_key]剩余:8
顾客302 抢购失败
顾客303 抢购失败
顾客304 抢购成功,[watch_key]剩余:7
顾客305 抢购失败
顾客306 抢购失败
顾客307 抢购成功,[watch_key]剩余:6
顾客308 抢购失败
顾客311 抢购成功,[watch_key]剩余:5
顾客309 抢购失败
顾客312 抢购失败
顾客310 抢购失败
顾客313 抢购失败
顾客314 抢购成功,[watch_key]剩余:4
顾客315 抢购失败
顾客316 抢购失败
顾客317 抢购成功,[watch_key]剩余:3
顾客318 抢购失败
顾客319 抢购失败
顾客320 抢购成功,[watch_key]剩余:2
顾客321 抢购失败
顾客322 抢购失败
顾客323 抢购成功,[watch_key]剩余:1
顾客324 抢购失败
顾客325 抢购失败
顾客326 抢购失败
顾客328商品售空,活动结束!
顾客327 抢购成功,[watch_key]剩余:0
顾客329商品售空,活动结束!
顾客330商品售空,活动结束!
......
Process finished with exit code 0

总结:~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,222评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,455评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,720评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,568评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,696评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,879评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,028评论 3 409
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,773评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,220评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,550评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,697评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,360评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,002评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,782评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,010评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,433评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,587评论 2 350

推荐阅读更多精彩内容