Redis扣庫存,主要目的是減少對資料庫的訪問,之前的減庫存,直接訪問資料庫,讀取庫存,當高並發請求到來的時候,大量的讀取資料有可能會導致資料庫的崩潰。
系統初始化的時候,將商品庫存載入到Redis 快取中儲存。
收到請求的時候,先在Redis中拿到該商品的庫存值,進行庫存預減,如果減完之後庫存不足,直接返回邏輯Exception就不需要訪問資料庫再去減庫存了,如果庫存值正確,進行下一步。
將請求入隊,立即給前端傳回一個值,表示正在排隊中,然後進行秒殺邏輯,後端隊列進行秒殺邏輯,前端輪詢後端發來的請求,如果秒殺成功,返回秒殺,成功,不成功就返回失敗。
/** * 秒杀接口优化之--- 第一步: 系统初始化后就将所有商品库存放入 缓存 */ @Override public void afterPropertiesSet() throws Exception { List<GoodsVo> goods = goodsService.getGoodsList(); if (goods == null) { return; } for (GoodsVo goodsVo : goods) { redisService.set(GoodsKey.getId(), goodsVo.getStockCount()); isOverMap.put(goodsVo.getId(), false);//先初始化 每个商品都是false 就是还有 } }
/**秒杀接口优化之 ----第二步: 预减库存 从缓存中减库存 * 利用 redis 中的方法,减去库存,返回值为 减去1 之后的值 * */ long stock = redisService.decr(GoodsKey.getGoodsStock, "" + goodsId); /*这里判断不能小于等于,因为减去之后等于 说明还有是正常范围*/ if (stock < 0) { isOverMap.put(goodsId, true);//没有库存就设置 对应id 商品的map 为true return Result.error(CodeMsg.MIAO_SHA_NO_STOCK); }
整體的邏輯如下:
1.先將所有資料讀出來,初始化到快取中,並以stock goodid 的形成存入Redis。
2.在秒殺的時候,先進行預減庫存偵測,從redis中,利用decr 減去對應商品的庫存,如果庫存小於0,說明此時 庫存不足,則不需要存取資料庫。直接拋出異常即可。
我們上面也用到了isOverMap,這個是記憶體標記。
由於介面優化很多基於Redis的快取操作,當並發很高的時候,也會為Redis伺服器帶來很大的負擔,如果可以減少對Redis伺服器的訪問,也可以達到的最佳化的效果。
於是,可以加一個記憶體map,標記對應商品的庫存量是否還有,在訪問Redis之前,在map中拿到對應商品的庫存量標記,就可以不需要訪問Redis 就可以判斷沒有庫存了。
1.產生一個map,並在初始化的時候,將所有商品的id為鍵,標記false 存入map。
private Map<Long, Boolean> isOverMap = new HashMap<Long, Boolean>(); /** * 秒杀接口优化之--- 第一步: 系统初始化后就将所有商品库存放入 缓存 */ @Override public void afterPropertiesSet() throws Exception { List<GoodsVo> goods = goodsService.getGoodsList(); if (goods == null) { return; } for (GoodsVo goodsVo : goods) { redisService.set(GoodsKey.getGoodsStock, "" + goodsVo.getId(), goodsVo.getStockCount()); isOverMap.put(goodsVo.getId(), false);//先初始化 每个商品都是false 就是还有 } }
/**再优化: 优化 库存之后的请求不访问redis 通过判断 对应 map 的值 * */ boolean isOver = isOverMap.get(goodsId); if (isOver) { return Result.error(CodeMsg.MIAO_SHA_NO_STOCK); } if (stock < 0) { isOverMap.put(goodsId, true);//没有库存就设置 对应id 商品的map 为true }
2.在預減庫存之前,從map取標記,若標記為false,說明庫存
當庫存不足時,預先減少商品庫存並將其標記為true,表示該商品庫存不足。所有下方請求都會被攔截,無需透過造訪redis來進行預減庫存。
所以利用快取的整體想法如下:
將商品的庫存資料載入到內存,同時初始化記憶體標記,也就是把每個產品的id存放到map,都是初始化為false ,在每次需要執行秒殺邏輯之前,在在內存標記中取值,如果仍有庫存即map裡返回的為false,則執行秒殺邏輯,否則直接拋出異常。
同時扣減庫存時,需要判斷快取中的庫存數量是否仍大於0,如果小於等於0,則修改記憶體標記。
以上是怎麼透過redis實現減庫存的秒殺場景的詳細內容。更多資訊請關注PHP中文網其他相關文章!