diff --git a/mall-pms/pms-boot/src/main/java/com/youlai/mall/pms/common/constant/PmsConstants.java b/mall-pms/pms-boot/src/main/java/com/youlai/mall/pms/common/constant/PmsConstants.java index 126aa5ad7..4429cba63 100644 --- a/mall-pms/pms-boot/src/main/java/com/youlai/mall/pms/common/constant/PmsConstants.java +++ b/mall-pms/pms-boot/src/main/java/com/youlai/mall/pms/common/constant/PmsConstants.java @@ -9,4 +9,8 @@ public interface PmsConstants { String LOCKED_STOCK_PREFIX = "stock:locked:"; String LOCK_SKU_PREFIX="lock:sku:"; + + String PRODUCT_DETAIL_CACHE = "product:detail:cache:"; + + String LOCK_PRODUCT_DETAIL="lock:product:detail"; } diff --git a/mall-pms/pms-boot/src/main/java/com/youlai/mall/pms/config/ProductLocalCache.java b/mall-pms/pms-boot/src/main/java/com/youlai/mall/pms/config/ProductLocalCache.java new file mode 100644 index 000000000..60167dcd5 --- /dev/null +++ b/mall-pms/pms-boot/src/main/java/com/youlai/mall/pms/config/ProductLocalCache.java @@ -0,0 +1,42 @@ +package com.youlai.mall.pms.config; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.youlai.mall.pms.pojo.dto.app.ProductFormDTO; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import java.util.concurrent.TimeUnit; + +/** +* @author DaniR +* @version 1.0 +* @description 本地缓存设置 +* @createDate 2021/6/16 10:08 +*/ +@Slf4j +@Component +public class ProductLocalCache { + private Cache localCache = null; + + @PostConstruct + private void init(){ + localCache = CacheBuilder.newBuilder() + //设置本地缓存容器的初始容量 + .initialCapacity(10) + //设置本地缓存的最大容量 + .maximumSize(500) + //设置写缓存后多少秒过期 + .expireAfterWrite(60, TimeUnit.SECONDS).build(); + } + + + public void setLocalCache(String key, ProductFormDTO object){ + localCache.put(key,object); + } + + public ProductFormDTO get(String key){ + return localCache.getIfPresent(key); + } +} diff --git a/mall-pms/pms-boot/src/main/java/com/youlai/mall/pms/service/impl/ProductServiceImpl.java b/mall-pms/pms-boot/src/main/java/com/youlai/mall/pms/service/impl/ProductServiceImpl.java index 6a0b71cdb..f436a5a68 100644 --- a/mall-pms/pms-boot/src/main/java/com/youlai/mall/pms/service/impl/ProductServiceImpl.java +++ b/mall-pms/pms-boot/src/main/java/com/youlai/mall/pms/service/impl/ProductServiceImpl.java @@ -5,58 +5,103 @@ import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.youlai.common.redis.utils.RedisUtils; +import com.youlai.mall.pms.config.ProductLocalCache; import com.youlai.mall.pms.mapper.PmsSpuMapper; +import com.youlai.mall.pms.pojo.dto.SpuDTO; import com.youlai.mall.pms.pojo.dto.app.ProductFormDTO; -import com.youlai.mall.pms.pojo.entity.PmsSpuAttributeValue; import com.youlai.mall.pms.pojo.entity.PmsSku; import com.youlai.mall.pms.pojo.entity.PmsSpec; import com.youlai.mall.pms.pojo.entity.PmsSpu; -import com.youlai.mall.pms.pojo.dto.SpuDTO; -import com.youlai.mall.pms.service.IPmsSpuAttributeValueService; +import com.youlai.mall.pms.pojo.entity.PmsSpuAttributeValue; import com.youlai.mall.pms.service.IPmsSkuService; import com.youlai.mall.pms.service.IPmsSpecService; +import com.youlai.mall.pms.service.IPmsSpuAttributeValueService; import com.youlai.mall.pms.service.IProductService; import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; import org.springframework.stereotype.Service; import java.util.List; +import static com.youlai.mall.pms.common.constant.PmsConstants.LOCK_PRODUCT_DETAIL; +import static com.youlai.mall.pms.common.constant.PmsConstants.PRODUCT_DETAIL_CACHE; + /** * @author haoxr * @date 2020-11-06 */ @Service +@Slf4j @AllArgsConstructor public class ProductServiceImpl extends ServiceImpl implements IProductService { - private IPmsSkuService iPmsSkuService; - private IPmsSpuAttributeValueService iPmsSpuAttributeValueService; - private IPmsSpecService iPmsSpecService; + private final IPmsSkuService iPmsSkuService; + private final IPmsSpuAttributeValueService iPmsSpuAttributeValueService; + private final IPmsSpecService iPmsSpecService; + private final RedisUtils redisUtils; + private final RedissonClient redissonClient; + private final ProductLocalCache productLocalCache; + @Override public ProductFormDTO getProductById(Long spuId) { - // spu - PmsSpu spu = this.getById(spuId); - SpuDTO SpuDTO = new SpuDTO(); - BeanUtil.copyProperties(spu, SpuDTO); - if (StrUtil.isNotBlank(spu.getPics())) { - // spu专辑图片转换处理 json字符串 -> List - List pics = JSONUtil.toList(JSONUtil.parseArray(spu.getPics()), String.class); - SpuDTO.setPics(pics); + //1、一级本地缓存设置 + ProductFormDTO product = productLocalCache.get(PRODUCT_DETAIL_CACHE + spuId); + if (null != product) { + log.info("get LocalCache product:" + product); + return product; } - // 属性 - List attrs = iPmsSpuAttributeValueService.list( - new LambdaQueryWrapper( - ).eq(PmsSpuAttributeValue::getSpuId, spuId) - ); + //2、二级缓存设置,Redis中获取商品详情信息 + product = (ProductFormDTO) redisUtils.get(PRODUCT_DETAIL_CACHE + spuId); + if (null != product) { + log.info("get redis product:" + product); + return product; + } + //3、分布式锁,保证原子操作 + RLock lock = redissonClient.getLock(LOCK_PRODUCT_DETAIL + spuId); + try { + if (lock.tryLock()) { + // spu + PmsSpu spu = this.getById(spuId); + SpuDTO SpuDTO = new SpuDTO(); + BeanUtil.copyProperties(spu, SpuDTO); + if (StrUtil.isNotBlank(spu.getPics())) { + // spu专辑图片转换处理 json字符串 -> List + List pics = JSONUtil.toList(JSONUtil.parseArray(spu.getPics()), String.class); + SpuDTO.setPics(pics); + } + // 属性 + List attrs = iPmsSpuAttributeValueService.list( + new LambdaQueryWrapper( + ).eq(PmsSpuAttributeValue::getSpuId, spuId) + ); + // 规格 + List specs = iPmsSpecService.listBySpuId(spuId); + // sku + List skuList = iPmsSkuService.list(new LambdaQueryWrapper().eq(PmsSku::getSpuId, spuId)); - // 规格 - List specs = iPmsSpecService.listBySpuId(spuId); - - // sku - List skuList = iPmsSkuService.list(new LambdaQueryWrapper().eq(PmsSku::getSpuId, spuId)); - - ProductFormDTO product = new ProductFormDTO(SpuDTO, attrs, specs, skuList); + product = new ProductFormDTO(SpuDTO, attrs, specs, skuList); + //TODO 4、需要判断商品是否是秒杀商品,根据秒杀信息更新商品秒杀相关信息 + log.info("get db product:" + product); + redisUtils.set(PRODUCT_DETAIL_CACHE + spuId, product, 3600); + productLocalCache.setLocalCache(PRODUCT_DETAIL_CACHE + spuId,product); + } else { + log.info("get redis2 product:" + product); + product = (ProductFormDTO) redisUtils.get(PRODUCT_DETAIL_CACHE + spuId); + if (null!=product) { + productLocalCache.setLocalCache(PRODUCT_DETAIL_CACHE + spuId, product); + } + } + } finally { + if (lock.isLocked()) { + if (lock.isHeldByCurrentThread()) { + lock.unlock(); + } + } + } return product; } }