一、问题描述
在日常使用的app中,基本都会有【收藏】功能,本文将介绍项目实战过程中收藏功能所采用的技术方案,其核心思想为使用【快照】,快照可采用json实现。
二、功能实现
2.1表设计
数据表的核心字段为用户iduserId
、业务IDbusinessId
、快照信息snapshot
、收藏内容类型 type
、收藏状态status
。数据表DDL如下:
create table t_favorite
(
id bigint auto_increment comment '主键'
primary key,
userId bigint not null comment '用户id',
business_id varchar(64) not null comment '业务ID',
`snapshot` json not null comment '快照信息',
`status` int default 0 not null comment '变更状态,如已下架',
`type` varchar(8) default '' not null comment '收藏类型',
...
constraint uk_userid_type_businessid
unique (user_id, `type`, business_id)
)
comment '收藏夹';
数据表使用用户id、收藏类型、业务id作为唯一索引,用以防止用户快速多次点击导致的重复收藏问题,也可考虑其他防重方案,如前端防重、分布式锁等。
2.2代码实现
2.2.1实体类
收藏实体类如下所示:
public class Favorit {
private Long id;
private Long userId;
private String businessId;
@TableField(typeHandler = FastjsonTypeHandler.class)
private JSONObject snapshot;
private String type;
private Integer status;
}
snapshot字段注解需要实现配置类,具体可参考文章:MySQL存入和解析JSON字符串
入参类如下所示:
@Data
public class FavoriteReq {
private Long userId;
private String businessId;
private JSONObject snapshot;
private Integer status;
private String type;
private Long minId;
private List<Long> businessIds;
}
2.2.2分页实现
收藏列表一般为按收藏时间倒序查询,即自增id由小到大排序,由此,为提升分页查询效率,可采用最小IDminId
来做分页,具体如下:
- 假设分页大小为每页10条数据;
- 首次查询时minId传0,可以拿到当前收藏的id最大的10条数据,后续查询时minId为上一次查询查到的最小id;
- 例:有100条数据,首次查询时传minId为0,查到数据的id范围为100-91,则第二次查询时minId为91,查到的数据id范围为90-81,以此类推,即可实现分页。
分页代码如下:
public List<Favorite> listFavorite(FavoriteReq favoriteReq) {
Page<Favorite> page = new Page(1, 10);
LambdaQueryWrapper<Favorite> wrapper = Wrappers.lambdaQuery(Favorite.class)
.eq(Favorite::getUserId, favoriteReq.getUserId())
.eq(Favorite::getType, favoriteReq.getType())
.eq(favoriteReq.getBusinessId() != null, Favorite::getBusinessId, favoriteReq.getBusinessId())
.lt(favoriteReq.getMinId() != null && favoriteReq.getMinId() > 0 ,Favorite::getId, favoriteReq.getMinId())
.orderByDesc(Favorite::getId);
List<Favorite> favorites = favoriteRepository.list(page, wrapper);
return favorites;
}
2.3分库分表方案
TODO。。。
三、结果示例
postman调用查询结果如下所示:
{
"code": "200",
"message": "ok",
"extraCode": "",
"extraMessage": "",
"tracestack": null,
"url": null,
"data": [
{
"businessId": "1234",
"snapshot": {
"title": " 菜篮子",
"firstCategoryName": "餐饮",
"telPhone": "12345678900",
"infoDTO": {
"salesTips": "半年销量500+",
"subTitle": "",
"submitJumpUrl": "https://www.baidu.com",
"tag": "",
"title": "",
"support": 0
}
},
"status": 1,
"type": "brand",
"id": "25"
}
]
}