商品中心—3.商品可采可补可售的技术文档上
大纲
1.可采可补可售业务的数据库建模设计
2.定时同步可采商品
3.定时同步可补商品
4.定时同步可售商品
5.商品中心架构梳理
1.可采可补可售业务的数据库建模设计
(1)可采可补可售
(2)可采业务表
(3)可补业务表
(4)可售业务表
(5)基础配置表
(1)可采可补可售
可售:配置了卖家组(售卖区)的商品,在该卖家组下的区域是可售状态
可补:可售商品,微仓是否可补,指⼤仓向微仓补货
可采:可售商品,⼤仓是否可采,指⼤仓采购
(2)可采业务表
一.商品与卖家组关系表
二.组套商品与SKU关系表
三.商品ITEM表
四.商品SKU表
五.商品⽆需采购配置表
一.商品与卖家组关系表
CREATE TABLE `sku_seller_relation` (`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主健',`item_id` varchar(40) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT 'itemId',`sku_id` varchar(40) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT 'skuId',`seller_group_id` varchar(50) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '卖家组ID',`seller_type` int(10) DEFAULT '0' COMMENT '卖家类型(1-⾃营,2-POP)',`relation_type` tinyint(3) DEFAULT '0' COMMENT '关系类型(1-可售,2-屏蔽)',`del_flag` tinyint(1) DEFAULT '1' COMMENT '删除标记(1-有效,0-删除)',`create_user` int(10) DEFAULT '0' COMMENT '创建⼈',`create_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',`update_user` int(10) DEFAULT '0' COMMENT '更新⼈',`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='商品与卖家组关系表';
二.组套商品与SKU关系表
CREATE TABLE `stack_sku_relation` (`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',`sku_id` varchar(40) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '售卖sku(组套商品)',`stack_sku_id` varchar(40) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '普通商品skuId或原料商品skuId',`stack_num` int(10) NOT NULL DEFAULT '0' COMMENT '数量',`channel` tinyint(3) NOT NULL DEFAULT '0' COMMENT '渠道(1-每日⽣鲜、2-美团、3-饿了么、4-淘鲜达、5-招商银⾏)',`seller_type` int(10) NOT NULL DEFAULT '0' COMMENT '卖家类型(1-⾃营,2-POP)',`features` varchar(500) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '扩展字段',`version_id` int(10) NOT NULL DEFAULT '0' COMMENT '版本号',`del_flag` tinyint(1) NOT NULL DEFAULT '0' COMMENT '删除标记(1-有效,0-删除)',`create_user` int(10) NOT NULL DEFAULT '0' COMMENT '创建⼈',`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',`update_user` int(10) NOT NULL DEFAULT '0' COMMENT '更新⼈',`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更改时间',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='组套商品与SKU关系表';
三.商品ITEM表
CREATE TABLE `item_info` (`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',`item_id` varchar(40) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '商品ID',`item_name` varchar(255) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '商品名称',`recommend` varchar(255) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '推荐语',`item_type` int(10) NOT NULL DEFAULT '0' COMMENT '商品类型',`channel` tinyint(3) NOT NULL DEFAULT '0' COMMENT '渠道(1-每日⽣鲜、2-美团、3-饿了么、4-淘鲜达、5-招商银⾏)',`seller_type` int(10) NOT NULL DEFAULT '0' COMMENT '卖家类型(1-⾃营,2-POP)',`producing_area_id` int(10) NOT NULL DEFAULT '0' COMMENT '产地ID',`item_status` int(10) NOT NULL DEFAULT '0' COMMENT '商品状态',`brand_id` int(10) NOT NULL DEFAULT '0' COMMENT '品牌ID',`shelf_life` int(10) NOT NULL DEFAULT '0' COMMENT '保质期(⼩时)',`store_condition_type` int(10) NOT NULL DEFAULT '0' COMMENT '存储条件',`category_id` int(10) NOT NULL DEFAULT '0' COMMENT '末级品类ID',`first_category_id` int(10) NOT NULL DEFAULT '0' COMMENT '⼀级品类ID',`second_category_id` int(10) NOT NULL DEFAULT '0' COMMENT '⼆级品类ID',`third_category_id` int(10) NOT NULL DEFAULT '0' COMMENT '三级品类ID',`item_specs_value` varchar(2048) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '规格值([{"颜⾊":"⾦⾊", "内存":"128g"},{"颜⾊":"银⾊", "内存":"256g"}])',`features` varchar(500) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '扩展字段',`version_id` int(10) NOT NULL DEFAULT '0' COMMENT '版本号',`del_flag` tinyint(1) NOT NULL DEFAULT '0' COMMENT '删除标记(1-有效,0-删除)',`create_user` int(10) NOT NULL DEFAULT '0' COMMENT '创建⼈',`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',`update_user` int(10) NOT NULL DEFAULT '0' COMMENT '更新⼈',`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8 COMMENT='商品ITEM表';
四.商品SKU表
CREATE TABLE `sku_info` (`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',`sku_id` varchar(40) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT 'skuId',`item_id` varchar(40) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT 'itemId',`sku_name` varchar(255) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT 'sku名称',`sku_type` int(10) NOT NULL DEFAULT '0' COMMENT 'sku类型(与item保持⼀致)',`base_price` int(10) NOT NULL DEFAULT '0' COMMENT '商城价格(单位:分)',`vip_price` int(10) NOT NULL DEFAULT '0' COMMENT '会员价格(单位:分)',`sku_grade` int(10) NOT NULL DEFAULT '0' COMMENT '商品分级(ABC标签,运营归类处理)',`channel` tinyint(3) NOT NULL DEFAULT '0' COMMENT '渠道(1-每日⽣鲜、2-美团、3-饿了么、4-淘鲜达、5-招商银⾏)',`seller_type` int(10) NOT NULL DEFAULT '0' COMMENT '卖家类型(1-⾃营,2-POP)',`sku_specs_value` varchar(2048) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '规格值({"颜⾊":"⾦⾊", "内存":"128g"})',`features` varchar(500) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '扩展字段',`version_id` int(10) NOT NULL DEFAULT '0' COMMENT '版本号',`del_flag` tinyint(1) NOT NULL DEFAULT '0' COMMENT '删除标记(1-有效,0-删除)',`create_user` int(10) NOT NULL DEFAULT '0' COMMENT '创建⼈',`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',`update_user` int(10) NOT NULL DEFAULT '0' COMMENT '更新⼈',`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更改时间',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8 COMMENT='商品SKU表';
五.商品⽆需采购配置表
CREATE TABLE `item_procurement_config` (`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',`category_id` int(10) NOT NULL DEFAULT '0' COMMENT '品类ID',`procurement_type` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否需要采购(1-需要,0-⽆需)',`version_id` int(10) NOT NULL DEFAULT '0' COMMENT '版本号',`del_flag` tinyint(1) NOT NULL DEFAULT '0' COMMENT '删除标记(1-有效,0-删除)',`create_user` int(10) NOT NULL DEFAULT '0' COMMENT '创建⼈',`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',`update_user` int(10) NOT NULL DEFAULT '0' COMMENT '更新⼈',`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更改时间',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8 COMMENT='商品⽆需采购配置表';
(3)可补业务表
一.商品ITEM表
二.组套商品与SKU关系表
三.商品与卖家组关系表
四.商品属性扩展表
一.商品ITEM表
CREATE TABLE `item_info` (`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',`item_id` varchar(40) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '商品ID',`item_name` varchar(255) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '商品名称',`recommend` varchar(255) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '推荐语',`item_type` int(10) NOT NULL DEFAULT '0' COMMENT '商品类型',`channel` tinyint(3) NOT NULL DEFAULT '0' COMMENT '渠道(1-每日⽣鲜、2-美团、3-饿了么、4-淘鲜达、5-招商银⾏)',`seller_type` int(10) NOT NULL DEFAULT '0' COMMENT '卖家类型(1-⾃营,2-POP)',`producing_area_id` int(10) NOT NULL DEFAULT '0' COMMENT '产地ID',`item_status` int(10) NOT NULL DEFAULT '0' COMMENT '商品状态',`brand_id` int(10) NOT NULL DEFAULT '0' COMMENT '品牌ID',`shelf_life` int(10) NOT NULL DEFAULT '0' COMMENT '保质期(⼩时)',`store_condition_type` int(10) NOT NULL DEFAULT '0' COMMENT '存储条件',`category_id` int(10) NOT NULL DEFAULT '0' COMMENT '末级品类ID',`first_category_id` int(10) NOT NULL DEFAULT '0' COMMENT '⼀级品类ID',`second_category_id` int(10) NOT NULL DEFAULT '0' COMMENT '⼆级品类ID',`third_category_id` int(10) NOT NULL DEFAULT '0' COMMENT '三级品类ID',`item_specs_value` varchar(2048) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '规格值([{"颜⾊":"⾦⾊", "内存":"128g"},{"颜⾊":"银⾊", "内存":"256g"}])',`features` varchar(500) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '扩展字段',`version_id` int(10) NOT NULL DEFAULT '0' COMMENT '版本号',`del_flag` tinyint(1) NOT NULL DEFAULT '0' COMMENT '删除标记(1-有效,0-删除)',`create_user` int(10) NOT NULL DEFAULT '0' COMMENT '创建⼈',`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',`update_user` int(10) NOT NULL DEFAULT '0' COMMENT '更新⼈',`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8 COMMENT='商品ITEM表';
二.组套商品与SKU关系表
CREATE TABLE `stack_sku_relation` (`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',`sku_id` varchar(40) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '售卖sku(组套商品)',`stack_sku_id` varchar(40) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '普通商品skuId或原料商品skuId',`stack_num` int(10) NOT NULL DEFAULT '0' COMMENT '数量',`channel` tinyint(3) NOT NULL DEFAULT '0' COMMENT '渠道(1-每日⽣鲜、2-美团、3-饿了么、4-淘鲜达、5-招商银⾏)',`seller_type` int(10) NOT NULL DEFAULT '0' COMMENT '卖家类型(1-⾃营,2-POP)',`features` varchar(500) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '扩展字段',`version_id` int(10) NOT NULL DEFAULT '0' COMMENT '版本号',`del_flag` tinyint(1) NOT NULL DEFAULT '0' COMMENT '删除标记(1-有效,0-删除)',`create_user` int(10) NOT NULL DEFAULT '0' COMMENT '创建⼈',`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',`update_user` int(10) NOT NULL DEFAULT '0' COMMENT '更新⼈',`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更改时间',PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='组套商品与SKU关系表';
三.商品与卖家组关系表
CREATE TABLE `sku_seller_relation` (`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主健',`item_id` varchar(40) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT 'itemId',`sku_id` varchar(40) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT 'skuId',`seller_group_id` varchar(50) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '卖家组ID',`seller_type` int(10) DEFAULT '0' COMMENT '卖家类型(1-⾃营,2-POP)',`relation_type` tinyint(3) DEFAULT '0' COMMENT '关系类型(1-可售,2-屏蔽)',`del_flag` tinyint(1) DEFAULT '1' COMMENT '删除标记(1-有效,0-删除)',`create_user` int(10) DEFAULT '0' COMMENT '创建⼈',`create_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',`update_user` int(10) DEFAULT '0' COMMENT '更新⼈',`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='商品与卖家组关系表';
四.商品属性扩展表
CREATE TABLE `attribute_extend` (`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',`participate_id` varchar(40) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '参与ID(ITEM_ID或SKU_ID)',`participate_type` int(10) NOT NULL DEFAULT '0' COMMENT '参与类型(1-ITEM,2-SKU)',`attribute_content` varchar(2048) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '属性内容',`feature` varchar(500) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '扩展字段',`version_id` int(10) NOT NULL DEFAULT '0' COMMENT '版本号',`del_flag` tinyint(1) NOT NULL DEFAULT '0' COMMENT '删除标记(1-有效,0-删除)',`create_user` int(10) NOT NULL DEFAULT '0' COMMENT '创建⼈',`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',`update_user` int(10) NOT NULL DEFAULT '0' COMMENT '更新⼈',`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',PRIMARY KEY (`ID`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COMMENT='商品属性扩展表';
(4)可售业务表
一.商品与卖家组关系表
二.商品卖家库存关系表
一.商品与卖家组关系表
CREATE TABLE `sku_seller_relation` (`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '主健',`item_id` varchar(40) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT 'itemId',`sku_id` varchar(40) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT 'skuId',`seller_group_id` varchar(50) CHARACTER SET utf8mb4 DEFAULT NULL COMMENT '卖家组ID',`seller_type` int(10) DEFAULT '0' COMMENT '卖家类型(1-⾃营,2-POP)',`relation_type` tinyint(3) DEFAULT '0' COMMENT '关系类型(1-可售,2-屏蔽)',`del_flag` tinyint(1) DEFAULT '1' COMMENT '删除标记(1-有效,0-删除)',`create_user` int(10) DEFAULT '0' COMMENT '创建⼈',`create_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '创建时间',`update_user` int(10) DEFAULT '0' COMMENT '更新⼈',`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='商品与卖家组关系表';
二.商品卖家库存关系表
CREATE TABLE `sku_stock_seller_relation` (`id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,`sku_id` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '商品ID',`seller_type` tinyint(3) NULL DEFAULT NULL COMMENT '卖家类型(1-⾃营,2-POP)',`seller_id` bigint(20) NULL DEFAULT NULL COMMENT '卖家ID',`stock_num` bigint(20) NULL DEFAULT NULL COMMENT '库存数量',`stock_unit` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '库存单位',`del_flag` tinyint(1) NULL DEFAULT NULL COMMENT '删除标记(1-有效,0-删除)',`create_user` int(11) NULL DEFAULT NULL COMMENT '创建⼈',`create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',`update_user` int(11) NULL DEFAULT NULL COMMENT '更新⼈',`update_time` datetime NULL DEFAULT NULL COMMENT '更新时间',PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO INCREMENT = 1 DEFAULT CHARSET=utf8 COMMENT='商品卖家库存关系表';
(5)基础配置表
leaf⾃增序列表leaf_alloc
CREATE TABLE `leaf_alloc` (`biz_tag` varchar(128) NOT NULL DEFAULT '' COMMENT '业务key',`max_id` bigint(20) NOT NULL DEFAULT '1' COMMENT '当前已经分配了的最⼤id',`step` int(11) NOT NULL COMMENT '初始步⻓,也是动态调整的最⼩步⻓',`description` varchar(256) DEFAULT NULL COMMENT '业务key的描述',`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '数据库维护的更新时间',PRIMARY KEY (`biz_tag`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='leaf⾃增序列表';
2.定时同步可采商品
(1)定时调度任务定时同步可采商品
(2)定时同步可采商品时的卖家组数据分页查询
(3)过滤无效的卖家组与查询卖家组支持的可售商品
(4)卖家组支持的可售商品十万级数据量查询实现
(5)根据卖家组支持的可售商品查询商品信息
(6)对可售商品进行无需采购以及生命周期过滤
(7)对卖家组支持的可售商品进行过滤组套商品
(8)将过滤后的商品数据与卖家组进行关联
(9)读取缓存与刷入缓存的逻辑
(10)卖家组支持的可采商品与缓存的diff逻辑
(11)基于DB的分段发号器组件
(1)定时调度任务定时同步可采商品
使用场景:定时任务调度,可以按不同的卖家类型分任务进⾏执⾏同步结果。
@Component
public class RecoverableJobHandler {@DubboReference(version = "1.0.0")private RecoverableApi recoverableApi;@XxlJob("syncRecoverableProduct")public void syncAvailableProduct(RecoverableRequest request) {XxlJobHelper.log("sync available product job starting...");JsonResult result = recoverableApi.syncRecoverableProduct(request);XxlJobHelper.log("sync available product job end, result:{}", result);}
}@DubboService(version = "1.0.0", interfaceClass = RecoverableApi.class, retries = 0)
public class RecoverableApiImpl implements RecoverableApi {@Autowiredprivate RecoverableService recoverableService;//同步可采商品@Overridepublic JsonResult syncRecoverableProduct(RecoverableRequest request) {try {return recoverableService.syncRecoverableProduct(request);} catch (ProductBizException e) {log.error("biz error: request={}", JSON.toJSONString(request), e);return JsonResult.buildError(e.getErrorCode(), e.getErrorMsg());} catch (Exception e) {log.error("system error: request={}", JSON.toJSONString(request), e);return JsonResult.buildError(e.getMessage());}}
}//商品可采业务实现类
@Service
public class RecoverableServiceImpl implements RecoverableService {...//同步可采的数据入缓存@Overridepublic JsonResult syncRecoverableProduct(RecoverableRequest request) {Integer pageNo = 1;//获取卖家类型对应的卖家组信息List<SellerGroupResponse> sellerGroupResponses = querySellerGroupList(pageNo, request.getSellerGroupType());while (!CollectionUtils.isEmpty(sellerGroupResponses)) {//1.过滤卖家组的非有效状态信息数据List<SellerGroupResponse> sellerGroupResponseList = sellerGroupFilter(sellerGroupResponses);//2.根据卖家组获取卖家支持的可售商品列表List<SkuSellerRelationDO> sellerRelationDOList = queryAvailableProduct(sellerGroupResponseList);//3.查询商品信息,并过滤非自营的商品List<ProductDetailDO> productDetailDOList = queryProductDetailList(sellerRelationDOList);//4.进行item级别的商品过滤(无需采购和生命周期)List<ProductDetailDO> itemFilterList = itemFilter(productDetailDOList);//5.进行组套商品的商品过滤(无需采购和生命周期)List<ProductDetailDO> suitFilterList = suitFilter(itemFilterList);//6.将详情的商品sku信息绑定到卖家上List<ProductSellerRelationBO> productSellerRelationBOList = buildBinding(sellerRelationDOList, suitFilterList);//7.读取历史的缓存信息,对已经存在的缓存进行diff处理并刷入缓存diffRecoverableCache(productSellerRelationBOList, sellerGroupResponses);pageNo++;sellerGroupResponses = querySellerGroupList(pageNo, request.getSellerGroupType());}return JsonResult.buildSuccess();}...
}
具体实现:
一.调⽤查询卖家信息接⼝,传⼊卖家类型,返回对应的卖家组信息列表
二.过滤掉返回的卖家组列表中⾮有效状态的卖家组
三.根据卖家组ID列表获取这些卖家组所⽀持售卖的商品
四.根据商品sku表sku_info查询得到⾃营类型的商品
五.根据商品⽆需采购配置表获取得到不需要采购的品类信息
六.根据sku列表批量查询⽣命周期的可采结果,并过滤不可采的商品信息七.进⾏组套商品验证,先通过sku批量查询组套商品与sku关系表
获取得到每个sku下的原料以及普通商品信息
对每个商品进⾏⽆需采购以及⽣命周期的验证
当组合商品下的sku都满⾜条件则可补,否则过滤
组套商品与SKU关系表是stack_sku_relation八.对已经存在的缓存数据和当前这次同步处理后的数据进⾏差集处理,发⽣变化的数据才需要刷⼊缓存(新增的或者⽆效的数据)
九.构建缓存模型,对可补的商品数据进⾏缓存,缓存的模型对象为:key为'前缀标识+卖家组ID',value为'可采sku+品类'
时序图:
流程图:
(2)定时同步可采商品时的卖家组数据分页查询
@Service
public class RecoverableServiceImpl implements RecoverableService {@Autowiredprivate SellerRemote sellerRemote;...//分页查询卖家组(售卖区)信息public List<SellerGroupResponse> querySellerGroupList(Integer pageNo, Integer sellerGroupType) {PageResult<SellerGroupResponse> sellerGroupPage = sellerRemote.getSellerGroupList(pageNo, CompensationConstants.SELLER_PAGE_SIZE, sellerGroupType);return sellerGroupPage.getContent();}//同步可采的数据入缓存@Overridepublic JsonResult syncRecoverableProduct(RecoverableRequest request) {Integer pageNo = 1;//获取卖家类型对应的卖家组信息List<SellerGroupResponse> sellerGroupResponses = querySellerGroupList(pageNo, request.getSellerGroupType());while (!CollectionUtils.isEmpty(sellerGroupResponses)) {//1.过滤卖家组的非有效状态信息数据List<SellerGroupResponse> sellerGroupResponseList = sellerGroupFilter(sellerGroupResponses);//2.根据卖家组获取卖家支持的可售商品列表List<SkuSellerRelationDO> sellerRelationDOList = queryAvailableProduct(sellerGroupResponseList);//3.查询商品信息,并过滤非自营的商品List<ProductDetailDO> productDetailDOList = queryProductDetailList(sellerRelationDOList);//4.进行item级别的商品过滤(无需采购和生命周期)List<ProductDetailDO> itemFilterList = itemFilter(productDetailDOList);//5.进行组套商品的商品过滤(无需采购和生命周期)List<ProductDetailDO> suitFilterList = suitFilter(itemFilterList);//6.将详情的商品sku信息绑定到卖家上List<ProductSellerRelationBO> productSellerRelationBOList = buildBinding(sellerRelationDOList, suitFilterList);//7.读取历史的缓存信息,对已经存在的缓存进行diff处理并刷入缓存diffRecoverableCache(productSellerRelationBOList, sellerGroupResponses);pageNo++;sellerGroupResponses = querySellerGroupList(pageNo, request.getSellerGroupType());}return JsonResult.buildSuccess();}...
}
(3)过滤无效的卖家组与查询卖家组支持的可售商品
@Service
public class RecoverableServiceImpl implements RecoverableService {...//对卖家组状态非有效的进行过滤private List<SellerGroupResponse> sellerGroupFilter(List<SellerGroupResponse> sellerGroupResponses) {//过滤无效的卖家组信息return sellerGroupResponses.stream().filter(sellerGroupResponse -> SellerGroupStatusEnum.EFFECTIVE_STATUS.getCode().equals(sellerGroupResponse.getSellerGroupStatus())).collect(Collectors.toList());}//返回卖家组支持的可售商品列表private List<SkuSellerRelationDO> queryAvailableProduct(List<SellerGroupResponse> sellerGroupResponses) {if (!CollectionUtils.isEmpty(sellerGroupResponses)) {//转换为所有的卖家组IDList<Long> sellerGroupIds = sellerGroupResponses.stream().map(SellerGroupResponse::getSellerGroupId).collect(Collectors.toList());//分页批量查询卖家组支持的可售商品列表return productRelationRepository.pageQueryAvailableProduct(sellerGroupIds);}return new ArrayList<>();}...
}
(4)卖家组支持的可售商品十万级数据量查询实现
一个SkuSellerRelationDO对象大概就50Byte,10万个SkuSellerRelationDO对象大概就是500万Byte=4MB。
@Repository
public class ProductRelationRepository {...//分页查询 卖家组ID 可售商品信息public List<SkuSellerRelationDO> pageQueryAvailableProduct(List<Long> sellerGroupIds) {//默认集合初始大小为50000,避免扩容次数频繁,一般商品的数量最多也就是几万-几十万List<SkuSellerRelationDO> sellerRelationAllList = new ArrayList<>(RecoverableConstants.SKU_INIT_NUM);//一次最大查询10 卖家组ID,多个分页查询,这里做数据切割List<List<Long>> splitList = DataCuttingUtil.dataCuttingString(sellerGroupIds, RecoverableConstants.SELLER_ID_LIMIT_NUM);for (List<Long> sellerGroupIdList : splitList) {List<SkuSellerRelationDO> productDetailDOList = queryAvailableProduct(sellerGroupIdList);if (!CollectionUtils.isEmpty(productDetailDOList)) {sellerRelationAllList.addAll(productDetailDOList);}}return sellerRelationAllList;}//根据卖家组ID 批量查询 可售商品信息public List<SkuSellerRelationDO> queryAvailableProduct(List<Long> sellerGroupIds) {//获取卖家组对应的可售商品LambdaQueryWrapper<SkuSellerRelationDO> queryWrapper = Wrappers.lambdaQuery();queryWrapper.in(SkuSellerRelationDO::getSellerGroupId, sellerGroupIds).eq(SkuSellerRelationDO::getRelationType, SkuSellerRelationTypeEnum.RELATION_TYPE_YES.getCode()).eq(SkuSellerRelationDO::getDelFlag, DelFlagEnum.EFFECTIVE.getCode());return skuSellerRelationMapper.selectList(queryWrapper);}...
}public class DataCuttingUtil {//对集合数据进行切割,切割的数量按传入切割大小计算public static <T> List<List<T>> dataCuttingString(List<T> splitList, Integer splitSize) {Integer size = splitList.size();//计算出可以切分出多少个集合对象int limit = (size + splitSize - 1) / splitSize;return Stream.iterate(0, n -> n + 1).limit(limit).parallel().map(a -> splitList.stream().skip((long) a * splitSize).limit(splitSize).parallel().collect(Collectors.toList())).collect(Collectors.toList());}...
}
(5)根据卖家组支持的可售商品查询商品信息
@Service
public class RecoverableServiceImpl implements RecoverableService {@Autowiredprivate ProductRepository productRepository;...//根据卖家组支持的可售商品,查询商品信息并过滤非自营的商品private List<ProductDetailDO> queryProductDetailList(List<SkuSellerRelationDO> sellerRelationDOList) {if (!CollectionUtils.isEmpty(sellerRelationDOList)) {//先获取到对应的skuID列表Set<String> skuIdList = sellerRelationDOList.stream().map(SkuSellerRelationDO::getSkuId).collect(Collectors.toSet());//一次最大查询1000skuId,多个分页查询,这里做数据切割List<ProductDetailDO> productDetailDOList = productRepository.pageQueryProductInfoList(skuIdList);if (!CollectionUtils.isEmpty(productDetailDOList)) {List<ProductDetailDO> productDetailDOS = productDetailDOList.stream().filter(productDetailDO -> productDetailDO.getSellerType().equals(SellerTypeEnum.SELF.getCode())).collect(Collectors.toList());return productDetailDOS;}}return new ArrayList<>();}...
}@Repository
public class ProductRepository {...//分页查询sku信息public List<ProductDetailDO> pageQueryProductInfoList(Set<String> skuIdList) {//默认集合初始大小为50000,避免扩容次数频繁,一般商品的数量最多也就是几万-几十万List<ProductDetailDO> productDetailAllList = new ArrayList<>(RecoverableConstants.SKU_INIT_NUM);//一次最大查询1000skuId,多个分页查询,这里做数据切割List<Set<String>> splitList = DataCuttingUtil.dataCuttingString(skuIdList, RecoverableConstants.SKU_LIMIT_NUM);for (Set<String> skuIds : splitList) {List<ProductDetailDO> productDetailDOList = queryProductInfoList(skuIds);if (!CollectionUtils.isEmpty(productDetailDOList)) {productDetailAllList.addAll(productDetailDOList);}}return productDetailAllList;}//批量查询商品的详情信息public List<ProductDetailDO> queryProductInfoList(Set<String> skuId) {return skuInfoMapper.queryProductInfoList(skuId);}...
}public class DataCuttingUtil {//对集合数据进行切割,切割的数量按传入切割大小计算public static <T> List<List<T>> dataCuttingString(List<T> splitList, Integer splitSize) {Integer size = splitList.size();//计算出可以切分出多少个集合对象int limit = (size + splitSize - 1) / splitSize;return Stream.iterate(0, n -> n + 1).limit(limit).parallel().map(a -> splitList.stream().skip((long) a * splitSize).limit(splitSize).parallel().collect(Collectors.toList())).collect(Collectors.toList());}...
}
(6)对可售商品进行无需采购以及生命周期过滤
@Service
public class RecoverableServiceImpl implements RecoverableService {...//进行item级别的商品过滤(无需采购和生命周期)private List<ProductDetailDO> itemFilter(List<ProductDetailDO> productDetailDOList) {if (!CollectionUtils.isEmpty(productDetailDOList)) {//过滤掉无需采购的商品列表List<ProductDetailDO> productDetailList = filterPurchaseProduct(productDetailDOList);//商品进行生命周期的查询检查,过滤不符合条件的商品return filterLifeCycle(productDetailList);}return productDetailDOList;}//过滤无需采购的item列表信息private List<ProductDetailDO> filterPurchaseProduct(List<ProductDetailDO> suitItemDOList) {//获取配置的无需采购的列表List<ItemProcurementConfigDO> itemProcurementConfigList = productConfigRepository.queryProcurementConfigList();//空集合判断if (CollectionUtils.isEmpty(suitItemDOList)) {return new ArrayList();}if (CollectionUtils.isEmpty(itemProcurementConfigList)) {return suitItemDOList;}//集合转map,方便验证是否命中Map<Integer, ItemProcurementConfigDO> procurementConfigMap = itemProcurementConfigList.stream().collect(Collectors.toMap(ItemProcurementConfigDO::getCategoryId, Function.identity()));//开始过滤无需采购的商品信息List<ProductDetailDO> productDetailDOList = suitItemDOList.stream().filter(productDetail -> !procurementConfigMap.containsKey(productDetail.getCategoryId())).collect(Collectors.toList());//返回过滤后的商品信息return productDetailDOList;}//进行商品生命周期的过滤private List<ProductDetailDO> filterLifeCycle(List<ProductDetailDO> productDetailList) {if (!CollectionUtils.isEmpty(productDetailList)) {//构建调用生命周期的接口入参模型Set<String> itemIdList = productDetailList.stream().map(ProductDetailDO::getItemId).collect(Collectors.toSet());List<ItemExpriResultDTO> skuExpriResultDTOS = itemPeriodStageRemote.queryByItemIds(itemIdList);//集合转map,方便验证是否命中Map<String, ItemExpriResultDTO> itemExpriResultMap = skuExpriResultDTOS.stream().collect(Collectors.toMap(ItemExpriResultDTO::getItemId, Function.identity()));//过滤不符合条件的商品List<ProductDetailDO> productDetailDOList = productDetailList.stream().filter(productDetail -> {//没有命中不保留if (!itemExpriResultMap.containsKey(productDetail.getItemId())) {return false;}ItemExpriResultDTO itemExpriResultDTO = itemExpriResultMap.get(productDetail.getItemId());//可采的状态返回truereturn itemExpriResultDTO.getPurchaseStatus().equals(ItemExpriEnum.RECOVERABLE_STATUS_YES.getCode());}).collect(Collectors.toList());//返回过滤后的商品信息return productDetailDOList;}return productDetailList;}...
}
(7)对卖家组支持的可售商品进行过滤组套商品
@Service
public class RecoverableServiceImpl implements RecoverableService {...//进行组套商品的商品过滤(无需采购和生命周期)private List<ProductDetailDO> suitFilter(List<ProductDetailDO> productDetailList) {if (!CollectionUtils.isEmpty(productDetailList)) {//1.查询哪些是组套商品,并且反向寻找到组套商品归属的item信息List<ProductDetailDO> suitItemDOList = querySuitList(productDetailList);//2.过滤掉无需采购的商品列表List<ProductDetailDO> productDetailDOList = filterSuitPurchaseProduct(suitItemDOList);//3.商品进行生命周期的查询检查,过滤不符合条件的商品return filterSuitLifeCycle(productDetailDOList);}return productDetailList;}//通过商品明细,查询出哪些是组套商品,并输出对应的归属item数据结构private List<ProductDetailDO> querySuitList(List<ProductDetailDO> productDetailDOList) {//根据skuId批量查询是否组套商品List<StackSkuRelationDO> stackSkuRelationAllList = queryStackSkuListByIds(productDetailDOList);//没有组套商品的直接返回if (CollectionUtils.isEmpty(stackSkuRelationAllList)) {return productDetailDOList;}//返回组套商品的详情集合信息(包含item信息)List<ProductDetailDO> itemProductList = queryProductInfoList(stackSkuRelationAllList);//将组套商品绑定到上级对应商品下return buildSuitBinding(itemProductList, productDetailDOList, stackSkuRelationAllList);}//根据skuId批量查询是否组套商品private List<StackSkuRelationDO> queryStackSkuListByIds(List<ProductDetailDO> productDetailDOList) {//先获取到对应的skuID列表Set<String> skuIdList = productDetailDOList.stream().map(ProductDetailDO::getSkuId).collect(Collectors.toSet());return productRelationRepository.pageQueryStackSkuListByIds(skuIdList);}//获取组套商品的详情集合信息private List<ProductDetailDO> queryProductInfoList(List<StackSkuRelationDO> stackSkuRelationAllList) {//获取组套商品的sku列表,通过sku列表联合查询得到对应的item信息Set<String> stackSkuIdList = stackSkuRelationAllList.stream().map(StackSkuRelationDO::getStackSkuId).collect(Collectors.toSet());//查询组套商品详情集合信息return productRepository.pageQueryProductInfoList(stackSkuIdList);}//将组套商品绑定上private List<ProductDetailDO> buildSuitBinding(List<ProductDetailDO> itemProductList, List<ProductDetailDO> productDetailDOList, List<StackSkuRelationDO> stackSkuRelationAllList) {List<ProductDetailDO> productSellerRelationBOList = recoverableConverter.converterProductList(productDetailDOList);//sku对应的组套商品详情(对应组套商品的stackSkuId)Map<String, ProductDetailDO> productDetailMap = itemProductList.stream().collect(Collectors.toMap(ProductDetailDO::getSkuId, Function.identity()));//组套的商品集合(一个商品下多个物料sku组装而成)Map<String, List<StackSkuRelationDO>> stackSkuRelationMap = stackSkuRelationAllList.stream().collect(Collectors.groupingBy(StackSkuRelationDO::getSkuId));for (ProductDetailDO productDetailDO : productSellerRelationBOList) {//命中到了对应的组套商品if (stackSkuRelationMap.containsKey(productDetailDO.getSkuId())) {List<ProductDetailDO> productDetailDOS = new ArrayList<>();//标记为组套商品productDetailDO.setProductType(2);//同时存储对应的组套商品详情信息List<StackSkuRelationDO> stackSkuRelationList = stackSkuRelationMap.get(productDetailDO.getSkuId());for (StackSkuRelationDO stackSkuRelationDO : stackSkuRelationList) {if (productDetailMap.containsKey(stackSkuRelationDO.getStackSkuId())) {ProductDetailDO productDetail = productDetailMap.get(stackSkuRelationDO.getStackSkuId());productDetailDOS.add(productDetail);}}productDetailDO.setProductDetailList(productDetailDOS);}}return productSellerRelationBOList;}//过滤无需采购的组套商品private List<ProductDetailDO> filterSuitPurchaseProduct(List<ProductDetailDO> suitItemDOList) {//获取配置的无需采购的列表List<ItemProcurementConfigDO> itemProcurementConfigList = productConfigRepository.queryProcurementConfigList();//空集合判断if (CollectionUtils.isEmpty(suitItemDOList)) {return new ArrayList();}if (CollectionUtils.isEmpty(itemProcurementConfigList)) {return suitItemDOList;}//集合转map,方便验证是否命中Map<Integer, ItemProcurementConfigDO> procurementConfigMap = itemProcurementConfigList.stream().collect(Collectors.toMap(ItemProcurementConfigDO::getCategoryId, Function.identity()));List<ProductDetailDO> productDetailDOList = new ArrayList<>(suitItemDOList.size());for (ProductDetailDO productDetailDO : suitItemDOList) {if (productDetailDO.getProductType().equals(2)) {List<ProductDetailDO> productDetailList = productDetailDO.getProductDetailList();//组套商品有商品不满足条件if (checkSuitPurchaseProduct(productDetailList, procurementConfigMap)) {continue;}}productDetailDOList.add(productDetailDO);}return productDetailDOList;}//进行组套商品生命周期的过滤private List<ProductDetailDO> filterSuitLifeCycle(List<ProductDetailDO> productDetailList) {List<ProductDetailDO> productDetailDOAllList = new ArrayList<>(productDetailList.size());if (!CollectionUtils.isEmpty(productDetailList)) {//查询返回生命周期的数据模型Map<String, ItemExpriResultDTO> itemExpriResultMap = queryItemExpriMap(productDetailList);for (ProductDetailDO productDetailDO : productDetailList) {if (productDetailDO.getProductType().equals(2)) {List<ProductDetailDO> productDetailDOList = productDetailDO.getProductDetailList();if (checkSuitLifeCycle(productDetailDOList, itemExpriResultMap)) {continue;}}productDetailDOAllList.add(productDetailDO);}}return productDetailDOAllList;}...
}
(8)将过滤后的商品数据与卖家组进行关联
@Service
public class RecoverableServiceImpl implements RecoverableService {...//同步可采的数据入缓存@Overridepublic JsonResult syncRecoverableProduct(RecoverableRequest request) {Integer pageNo = 1;//获取卖家类型对应的卖家组信息List<SellerGroupResponse> sellerGroupResponses = querySellerGroupList(pageNo, request.getSellerGroupType());while (!CollectionUtils.isEmpty(sellerGroupResponses)) {//1.过滤卖家组的非有效状态信息数据List<SellerGroupResponse> sellerGroupResponseList = sellerGroupFilter(sellerGroupResponses);//2.根据卖家组获取卖家支持的可售商品列表List<SkuSellerRelationDO> sellerRelationDOList = queryAvailableProduct(sellerGroupResponseList);//3.查询商品信息,并过滤非自营的商品List<ProductDetailDO> productDetailDOList = queryProductDetailList(sellerRelationDOList);//4.进行item级别的商品过滤(无需采购和生命周期)List<ProductDetailDO> itemFilterList = itemFilter(productDetailDOList);//5.进行组套商品的商品过滤(无需采购和生命周期)List<ProductDetailDO> suitFilterList = suitFilter(itemFilterList);//6.将详情的商品sku信息绑定到卖家上List<ProductSellerRelationBO> productSellerRelationBOList = buildBinding(sellerRelationDOList, suitFilterList);//7.读取历史的缓存信息,对已经存在的缓存进行diff处理并刷入缓存diffRecoverableCache(productSellerRelationBOList, sellerGroupResponses);pageNo++;sellerGroupResponses = querySellerGroupList(pageNo, request.getSellerGroupType());}return JsonResult.buildSuccess();}//将过滤后的商品明细绑定到卖家组上private List<ProductSellerRelationBO> buildBinding(List<SkuSellerRelationDO> sellerRelationDOList, List<ProductDetailDO> productDetailDOList) {//先转换集合为map,key为商品的skuId标识Map<String, ProductDetailDO> skuInfoDOMap = productDetailDOList.stream().collect(Collectors.toMap(ProductDetailDO::getSkuId, Function.identity()));//按卖家组ID进行分组,把下属的商品合并到一个上Map<Long, List<SkuSellerRelationDO>> skuSellerRelationMap = sellerRelationDOList.stream().collect(Collectors.groupingBy(SkuSellerRelationDO::getSellerGroupId));//返回的绑定卖家组和商品明细的集合对象List<ProductSellerRelationBO> sellerRelationBOList = new ArrayList<>(sellerRelationDOList.size());//遍历卖家和商品关系集合,开始填充商品sku信息绑定到卖家组上for (Map.Entry<Long, List<SkuSellerRelationDO>> entry : skuSellerRelationMap.entrySet()) {List<SkuSellerRelationDO> skuSellerRelationDOS = entry.getValue();Long sellerGroupId = entry.getKey();//循环绑定卖家组下的商品关系ProductSellerRelationBO productSellerRelationBO = new ProductSellerRelationBO();productSellerRelationBO.setSellerId(sellerGroupId);List<ProductDetailDO> productDetailList = new ArrayList<>();//遍历卖家组下的可售商品列表for (SkuSellerRelationDO sellerRelationDO : skuSellerRelationDOS) {//查询的数据集合中 存在这个商品数据if (skuInfoDOMap.containsKey(sellerRelationDO.getSkuId())) {ProductDetailDO productDetailDO = skuInfoDOMap.get(sellerRelationDO.getSkuId());//绑定数据到卖家组上productDetailList.add(productDetailDO);}}productSellerRelationBO.setProductDetailList(productDetailList);sellerRelationBOList.add(productSellerRelationBO);}return sellerRelationBOList;}...
}