Redis 中的SortedSet结构非常适合用于实现实时榜单的场景,它根据成员的分数自动进行排序,支持高效的添加、更新和查询操作。
SortedSet实时榜单的一些典型应用场景:
游戏中的玩家排行榜:在多人在线游戏中,使用 SortedSet来维护玩家的得分排行榜,可以按照玩家的得分来排序,方便展示顶级玩家或者好友间的排名情况。
电商热销榜:像淘宝、京东等电商平台的热销商品榜单(例如热销手机、电脑等)。通过 SortedSet可以轻松维护基于销量或其他指标的商品排名,并能快速获取最新的排名信息。
体育赛事积分榜:在体育赛事的应用场景中,利用 SortedSet维护各队伍或运动员的比赛积分、胜率等统计数据的排行榜,以便实时更新和展示最新的排名情况。
下面我们来实战一下用户积分实时榜单!今天实战的内容有查看全部榜单(从大到小);查看前三名的榜单(从大到小);查看某个用户的排名;给某个用户加积分,之后返回所有榜单;查看个人的积分。
对象准备(记得重写HashCode与Equals方法):
public class UserPointVO {private String username;private String phone;public UserPointVO(String username, String phone) {this.username = username;this.phone = phone;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPhone() {return phone;}public void setPhone(String phone) {this.phone = phone;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;UserPointVO that = (UserPointVO) o;return phone.equals(that.phone);}@Overridepublic int hashCode() {return Objects.hash(phone);}
}
数据准备:
@Testvoid testData() {UserPointVO p1 = new UserPointVO("老A","324");UserPointVO p2 = new UserPointVO("老B","242");UserPointVO p3 = new UserPointVO("老C","542345");UserPointVO p4 = new UserPointVO("老D","235");UserPointVO p5 = new UserPointVO("老E","1245");UserPointVO p6 = new UserPointVO("老F","2356432");UserPointVO p7 = new UserPointVO("老G","532332");UserPointVO p8 = new UserPointVO("老H","13113");BoundZSetOperations<String, UserPointVO> operations = redisTemplate.boundZSetOps("point:rank:real");operations.add(p1,324);operations.add(p2,542);operations.add(p3,52);operations.add(p4,434);operations.add(p5,1123);operations.add(p6,64);operations.add(p7,765);operations.add(p8,8);}
redis中的数据:
我们首先开发返回全部榜单,从大到小的接口:
/***返回全部榜单,从大到小* @return*/@RequestMapping("real_rank1")public JsonData realRank1(){BoundZSetOperations<String, UserPointVO> operations = redisTemplate.boundZSetOps("point:rank:real");Set<UserPointVO> set = operations.reverseRange(0, -1);return JsonData.buildSuccess(set);}
打印结果为:
接着开发返回前三名榜单的接口:
/***返回指定大小榜单,从大到小,这里是返回前三名* @return*/@RequestMapping("real_rank2")public JsonData realRank2(){BoundZSetOperations<String, UserPointVO> operations = redisTemplate.boundZSetOps("point:rank:real");Set<UserPointVO> set = operations.reverseRange(0, 2);return JsonData.buildSuccess(set);}
打印结果为:
查看某个用户的排名:
/*** 查看某个用户的排名* @param name* @param phone* @return*/@RequestMapping("find_myrank")public JsonData realMyRank(String name,String phone){BoundZSetOperations<String, UserPointVO> operations = redisTemplate.boundZSetOps("point:rank:real");UserPointVO userPointVO = new UserPointVO(name,phone);long rank = operations.reverseRank(userPointVO);return JsonData.buildSuccess(++rank);}
这里我们查看老H的排名,打印结果为:
给某个用户加积分:
/*** 给某个用户加积分,之后返回所有榜单* @param name* @param phone* @param point* @return*/@RequestMapping("uprank")public JsonData upRank(String name,String phone,int point){BoundZSetOperations<String, UserPointVO> operations = redisTemplate.boundZSetOps("point:rank:real");UserPointVO userPointVO = new UserPointVO(name,phone);operations.incrementScore(userPointVO,point);Set<UserPointVO> set = operations.reverseRange(0, -1);return JsonData.buildSuccess(set);}
这里我们给老H加1000的积分,打印结果为:
查看个人的积分:
/*** 查看个人的积分* @param name* @param phone* @return*/@RequestMapping("mypoint")public JsonData mypoint(String name,String phone){BoundZSetOperations<String, UserPointVO> operations = redisTemplate.boundZSetOps("point:rank:real");UserPointVO userPointVO = new UserPointVO(name,phone);double score = operations.score(userPointVO);return JsonData.buildSuccess(score);}
这里我们还是查看老H的积分: