天天看点

畅购04——商品管理(分布式ID)为何使用分布式ID项目中如何使用分布式ID搞清SPU和SKU的区别商品的CRUD

电商项目——CG

  • 为何使用分布式ID
  • 项目中如何使用分布式ID
  • 搞清SPU和SKU的区别
  • 商品的CRUD
    • 增加商品
    • 根据id查询商品
    • 修改商品
    • 审核商品
    • 商品上下架
    • 删除商品
    • 全局异常处理

为何使用分布式ID

  1. 我们学过UUID是唯一的,但是它是字符串,

    查询效率低。无法保证递增的趋势,不可读

  2. 也可用Redis来生成ID。这主要依赖于Redis是单线程的,所以也可以用生成全局唯一的ID。可以用Redis的原子操作 INCR和INCRBY来实现,但是

    网络传输会造成性能下降

  3. 而雪花算法(snowflake)的其核心思想是:使用前41bit作为毫秒数,中间10bit作为机器的ID(5个bit是数据中心,5个bit的机器ID),后12bit作为毫秒内的流水号(意味着每个节点在每毫秒可以产生 4096 个 ID),最前还有一个符号位,永远是0(二进制1为负数)。几乎完美解决了上述的问题。

项目中如何使用分布式ID

  1. 首先引入工具包IdWorker.java
  2. changgou_service_goods中yml配置:

    这两值只能在0~31之间

workerId: 0
datacenterId: 0
           
  1. 在启动类配置一个idWorker的Bean,以@Value将两个属性注进来。

搞清SPU和SKU的区别

  • 概念

    SPU:一个统称

    SKU:对SPU的细化,比如有颜色,内存大小等等

  • 就搞一个SKU不行吗?

    答案是:不行,因为对于单个商品(如小米10)的详情,图片,友情链接是一样的。SPU更加便于维护。

商品的CRUD

增加商品

  1. 商品Goods由spu和sku组成,所以在…-api中先创建Goods实体类
  2. spu业务层新增方法add(Goods goods),先存spu,再存sku。具体逻辑:

    - 生成分布式ID,重新封装spu(审核状态,删除状态,上架状态全为0),再调用方法spuMapper.insertSelective(spu)进行保存。

    - 存sku的时候注意两点,第一:分类与品牌的关联,如未建立则需在tb_category_brand添加数据,方便数据的维护。第二:skuList中拿到的spec是个json字符串,需要将其拿出来转成map取value的值再与name组合生成最终的name。再重新封装sku,向表中添加数据。sku所需数据如下:

private String sn;//商品条码
	private String name;//SKU名称
	private Integer price;//价格(分)
	private Integer num;//库存数量
	private Integer alertNum;//库存预警数量
	private String image;//商品图片
	private String images;//商品图片列表
	private Integer weight;//重量(克)
	private java.util.Date createTime;//创建时间
	private java.util.Date updateTime;//更新时间
	private String spuId;//SPUID
	private Integer categoryId;//类目ID
	private String categoryName;//类目名称
	private String brandName;//品牌名称
	private String spec;//规格
	private Integer saleNum;//销量
	private Integer commentNum;//评论数
	private String status;//商品状态 1-正常,2-下架,3-删除
           

根据id查询商品

  1. 根据id查询spu。
  2. 封装Example对象,然后根据id查询出所有的skuList。
  3. 创建Goods对象,将spu和skuList一起放进对象中并返回。

修改商品

  1. 首先从goods中拿到spu,对spu进行修改
  2. 根据spu的id删除所有的sku,再重新增加(调用新增方法)

审核商品

  • 分析:

    先通过id查询到spu,如果spu为空或者删除状态为1,则抛一个

    系统异常(本篇的最后)

    ,否则就将spu的status和isMarketable设为1。
  • 代码如下:
@Transactional
    @Override
    public void audit(String id) {
        Spu spu = spuMapper.selectByPrimaryKey(id);
        if (spu==null || "1".equals(spu.getIsDelete())){
            throw new BusinessException(new Result(false, StatusCode.ERROR,"无此商品信息或处于删除状态"));
        }
        //审核
        spu.setStatus("1");
        //上架
        spu.setIsMarketable("1");
        spuMapper.updateByPrimaryKeySelective(spu);
    }
           

商品上下架

  • 分析:

    无论上下架都要先进行判断,根据id查询spu,若spu为空或者处于删除状态,或status为0都不可操作,抛一个系统异常。否则直接更改上架状态,代码简单,不做赘述。

删除商品

  • 逻辑删除(可还原)

    先做一个判断,未下架商品不能逻辑删除,下架后可直接更改删除状态为1。

    还原商品:当status为0或删除状态为0都不可操作,否则直接修改删除状态为0。

  • 物理删除

    根据id直接删除数据即可。

全局异常处理

主要利用了Aop思想,做了异常捕获类,代码如下:

/**
 * 统一异常处理类
 */
@ControllerAdvice
public class BaseExceptionHandler {
	//BusinessException继承了RuntimeExcption
    @ExceptionHandler(value = BusinessException.class)
    @ResponseBody
    public Result otherError(BusinessException e){
        e.printStackTrace();
        return e.getResult();
    }

    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public Result error(Exception e){
        e.printStackTrace();
        return new Result(false, StatusCode.ERROR, "执行出错");
    }
}