基于redis数据结构ZSET实现邀请人排行榜
- 背景:用户注册可以填写邀请人id,系统记录邀请人排行情况
- 方案:因为ZSET是一个天然有序的数据结构,我们可以把积分当做score,userId当做member,放到zset中,zset会默认按照SCORE进行排序的。
- 代码实现
maven依赖
<!-- Redisson -->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.24.3</version>
</dependency>
//用户注册
//更新排名(inviterId邀请人ID)
updateInviteRank(inviterId);
updateInviteRank的具体代码实现:
//定义RScoredSortedSet对象
private RScoredSortedSet<String> inviteRank;
//初始化
@Override
public void afterPropertiesSet() throws Exception {
this.inviteRank = redissonClient.getScoredSortedSet("inviteRank");
}
private void updateInviteRank(String inviterId) {
// 如果邀请者ID为空,则直接返回,不进行操作
if (inviterId == null) {
return;
}
// 获取Redisson的锁对象
RLock rLock = redissonClient.getLock(inviterId);
// 对邀请者ID对应的锁进行加锁操作,避免并发更新
rLock.lock();
try {
// 获取邀请者的当前排名分数
Double score = inviteRank.getScore(inviterId);
// 如果当前分数为空,则设置默认为0.0
if (score == null) {
score = 0.0;
}
// 将邀请者的排名分数增加100.0,并更新到排行榜中
inviteRank.add(score + 100.0, inviterId);
} finally {
// 最终释放邀请者ID对应的锁
rLock.unlock();
}
}
RScoredSortedSet提供了很多方法方便对ZSET进行操作,以下是一些常用的排行方法:
- Double getScore(V var1); 获取指定成员的分数。
- boolean add(double var1, V var3); 向有序集合中添加一个成员,指定该成员的分数。
- Integer rank(V var1); 获取指定成员在有序集合中的排名(从小到大排序,排名从 0 开始)。
- Integer revRank(V var1);获取指定成员在有序集合中的排名(从大到小排序,排名从 0 开始)。
- Collection<ScoredEntry> entryRange(int var1, int var2); 获取分数在指定范围内的成员及其分数的集合。
获取前N个用户的排名信息
//按照分数从高到低,获取前N个用户的排名信息
public List<InviteRankInfo> getTopN(Integer topN) {
Collection<ScoredEntry<String>> rankInfos = inviteRank.entryRangeReversed(0, topN - 1);
List<InviteRankInfo> inviteRankInfos = new ArrayList<>();
if (rankInfos != null) {
for (ScoredEntry<String> rankInfo : rankInfos) {
InviteRankInfo inviteRankInfo = new InviteRankInfo();
String userId = rankInfo.getValue();
if (StringUtils.isNotBlank(userId)) {
User user = findById(Long.valueOf(userId));
if (user != null) {
inviteRankInfo.setNickName(user.getNickName());
inviteRankInfo.setInviteCount(rankInfo.getScore().intValue() / 100);
inviteRankInfos.add(inviteRankInfo);
}
}
}
}
return inviteRankInfos;
}