唠嗑:网上瞎逛,看到秒杀活动,就发现自己没有了解过这方面的,就去网上查了实现方法,这里做个记录,顺便自己实现一下。
一、大体思路:提前把要进行秒杀的活动商品存入缓存中,秒杀成功或失败直接返回,秒杀成功,则异步执行下单操作。
二、这里主要是通过Redis事务以及watch防止超卖。
2.1先介绍一下watch机制
Redis Watch 命令用于监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。
【 以下是自己对于Redis事务以及watch防止超卖的理解。】
举个例子:两个线程同时进来了,第一个线程进来开启了事务,然后修改key值,同时第二线程也进来开启了事务,又再次在第一个线程执行事务之前修改了key值,则第一个线程执行事务就会失败,第二会执行成功。
就保证在取得同一个key值得情况下,只有一个线程可以执行成功。
2.2 补充Redis事务机制
用下面这张图补充一下,再开启事务后multi,操作key的命令会放入事务队列,在执行事务exec时,watch(key)发现在事务队列中key被其他命令修改了,则当前事务执行就会失败。
三、代码
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
总结:~