Jelajahi Sumber

修复销量的缓存击穿问题

chenbiao 7 bulan lalu
induk
melakukan
eac67180e9

+ 63 - 25
netflix-web/src/main/java/com/cyksj/web/controller/goods/GoodsDonController.java

@@ -345,28 +345,48 @@ public class GoodsDonController {
      */
     @GetMapping("/get/register")
     public Result<List<RegisterGoodsDonView>> getRegisterGoodsDon() {
-        String registerCacheKey = RedisService.key.REGISTER_HOME_PAGE_CACHE.getName();
-        Object value = redisService.get(registerCacheKey);
-        if (value != null) {
+        try {
+            String registerCacheKey = RedisService.key.REGISTER_HOME_PAGE_CACHE.getName();
+            Object value = redisService.get(registerCacheKey);
+            if (value != null) {
+                try {
+                    List<RegisterGoodsDonView> list = Jsons.parseList(value, RegisterGoodsDonView.class);
+                    if (CollUtil.isNotEmpty(list)) {
+                        return GatewayResponse.SUCCESS.newBuilder().toResult(list);
+                    }
+                } catch (Exception e) {
+                }
+            }
+            String lockKey = registerCacheKey + ":lock";
+            if (!redisService.setNx(lockKey, "1", 10L)) {
+                return GatewayResponse.SUCCESS.newBuilder().toResult(Collections.emptyList());
+            }
             try {
-                List<RegisterGoodsDonView> list = Jsons.parseList(value, RegisterGoodsDonView.class);
-                if (CollUtil.isNotEmpty(list)) {
-                    return GatewayResponse.SUCCESS.newBuilder().toResult(list);
+                value = redisService.get(registerCacheKey);
+                if (value != null) {
+                    List<RegisterGoodsDonView> list = Jsons.parseList(value, RegisterGoodsDonView.class);
+                    if (CollUtil.isNotEmpty(list)) {
+                        return GatewayResponse.SUCCESS.newBuilder().toResult(list);
+                    }
                 }
-            } catch (Exception e) {
+                MapBuilder builder = MapUtils.flatBuilder(request.getParameterMap());
+                List<RegisterGoodsDonView> dataList = beanSearcher.searchAll(RegisterGoodsDonView.class, builder.build());
+                DateTime now = DateTime.now();
+                dataList.forEach(data -> {
+                    Integer sold = registerOrderDonMapper.selectCount(Wrappers.lambdaQuery(RegisterOrderDon.class)
+                            .eq(RegisterOrderDon::getGoodsId, data.getId()).notIn(RegisterOrderDon::getStatus, Constant.noOrderStatus));
+                    data.setSold(sold + data.getVirtualSold());
+                    data.setNotifyMsg(getPayMsgTime(data.getId(), now, 2, null));
+                });
+                redisService.set(registerCacheKey, dataList, RedisService.key.REGISTER_HOME_PAGE_CACHE.getTimeout());
+                return GatewayResponse.SUCCESS.newBuilder().toResult(dataList);
+            } finally {
+                redisService.del(lockKey);
             }
+        } catch (Exception e) {
+            // Redis异常,返回空列表保护数据库
+            return GatewayResponse.SUCCESS.newBuilder().toResult(Collections.emptyList());
         }
-        MapBuilder builder = MapUtils.flatBuilder(request.getParameterMap());
-        List<RegisterGoodsDonView> dataList = beanSearcher.searchAll(RegisterGoodsDonView.class, builder.build());
-        DateTime now = DateTime.now();
-        dataList.forEach(data -> {
-            Integer sold = registerOrderDonMapper.selectCount(Wrappers.lambdaQuery(RegisterOrderDon.class)
-                    .eq(RegisterOrderDon::getGoodsId, data.getId()).notIn(RegisterOrderDon::getStatus, Constant.noOrderStatus));
-            data.setSold(sold + data.getVirtualSold());
-            data.setNotifyMsg(getPayMsgTime(data.getId(), now, 2, null));
-        });
-        redisService.setNx(registerCacheKey, dataList, RedisService.key.REGISTER_HOME_PAGE_CACHE.getTimeout());
-        return GatewayResponse.SUCCESS.newBuilder().toResult(dataList);
     }
 
 
@@ -1508,14 +1528,32 @@ public class GoodsDonController {
 	 * @return
 	 */
 	private Integer getGoodsSold(Long goodsId, Integer virtualSold) {
-		Object soldObj = redisService.get(RedisService.key.YH_HOME_PAGHE_CACHE.getName() + "sold:" + goodsId);
-		if (soldObj == null) {
-			Integer sold = orderDonMapper.selectCount(Wrappers.lambdaQuery(OrderDon.class)
-					.eq(OrderDon::getGoodsId, goodsId).notIn(OrderDon::getStatus, Constant.noOrderStatus));
-			soldObj = sold + virtualSold;
-			redisService.set(RedisService.key.YH_HOME_PAGHE_CACHE.getName() + "sold:" + goodsId, soldObj, RedisService.key.YH_HOME_PAGHE_CACHE.getTimeout());
+		try {
+			String cacheKey = RedisService.key.YH_HOME_PAGHE_CACHE.getName() + "sold:" + goodsId;
+			Object soldObj = redisService.get(cacheKey);
+			if (soldObj == null) {
+				String lockKey = cacheKey + ":lock";
+				if (redisService.setNx(lockKey, "1", 10L)) {
+					try {
+						soldObj = redisService.get(cacheKey);
+						if (soldObj == null) {
+							Integer sold = orderDonMapper.selectCount(Wrappers.lambdaQuery(OrderDon.class)
+									.eq(OrderDon::getGoodsId, goodsId).notIn(OrderDon::getStatus, Constant.noOrderStatus));
+							soldObj = sold + virtualSold;
+							redisService.set(cacheKey, soldObj, RedisService.key.YH_HOME_PAGHE_CACHE.getTimeout());
+						}
+					} finally {
+						redisService.del(lockKey);
+					}
+				} else {
+					return virtualSold;
+				}
+			}
+			return Integer.parseInt(soldObj.toString());
+		} catch (Exception e) {
+			// Redis异常,返回虚拟销量保护数据库
+			return virtualSold;
 		}
-		return Integer.parseInt(soldObj.toString());
 	}
 
 	/**