https://blog.csdn.net/u012809308/article/details/113572571
想做一个根据用户对商品的点赞数的排行榜,考虑到Redis 的zset 的可以根据分数排序,今天就来玩一下。文中使用springboot 的redisTemplate 操作redis,可以参考之前写的一篇操作redis 各种数据结构的文章:redisTemplate分别存取redis的string/list/set/zset/hash等数据类型 这里会用到里面介绍的redisTemplate.
首先建立一个实体类,用于测试,商品数据统一使用springboot jpa 进行操作:
@Data@Entity@Table(name = "tb_product")public class Product {@Id@Column(name = "id")private String id;@Column(name = "name")private String name;@Column(name = "price")private Double price;}
数据结构的设计:在redis 中建立一个zset 类型的key,其中的每个member 用商品的ID充当,分数使用用户对该商品的点赞数量表示,这样Redis就可以根据点赞数对库中的商品进行排序,从而我们可以顺利获取商品的点赞排行榜 。
用户每一次对商品点赞,我们就可以根据该商品的ID,增加zset中的该member的score,如果该member不存在就新增,如果存在直接增加其分数:
@Servicepublic class RedisRankService {@Autowiredprivate RedisTemplate redisTemplate;@Autowiredprivate ProductRepository productRepository;private String key = "product:praise";public void GiveAPraise(String id){ redisTemplate.opsForZSet().incrementScore(key,id,1); }}
利用zset 根据分数排序的特性,倒序取出(按照分数从大到小)就可以取出点赞数排行前10的商品ID,再根据商品ID到Redis中取出对应的点赞数,以及借助jpa从数据库中根据商品ID取出这些商品的全部信息就非常easy了。
public List<ProductVo> queryTop10Product(){ List<ProductVo> vos = new ArrayList<>(); Set<String> idSets = redisTemplate.opsForZSet().reverseRange(key, 0, 9); List<Product> products = productRepository.queryByIdIn(idSets); Map<String,Product> idProductMap = CollectionUtils.isEmpty(products)? Maps.newHashMap() : products.stream().collect(Collectors.toMap(Product::getId, Function.identity(),(e1,e2)->e2));for (String id : idSets){Double score = redisTemplate.opsForZSet().score(key, id);ProductVo vo = new ProductVo();Product p = idProductMap.getOrDefault(id,new Product()); vo.setId(id); vo.setName(p.getName()); vo.setPrice(p.getPrice()); vo.setScore(score.intValue()); vos.add(vo); }return vos; }
操作数据我们使用spingboot jpa, 对于一些简单的查询方法可以不用写SQL,直接使用jpa规定的关键词构造查询方法即可,比如这里根据批量的商品ID查询所有商品详情:
@Repositorypublic interface ProductRepository extends JpaRepository<Product,String>, JpaSpecificationExecutor<Product> { List<Product> queryByIdIn(Set ids);}