【Java】RedisTemplate来控制某段时间内执行最大次数

一、前言

RedisTemplate来控制某段时间内执行最大次数的Java示例代码。

二、使用场景

假设我们希望限制某个操作(如发送邮件、访问特定API等)在1小时内最多执行n次。

三、思路

  1. 使用redis的zset数据结构,将当前时间戳作为分值。
  2. 每次发送短信时,先删除1个小时以前的元素(即分值从0,一个小时前的时间戳)。
  3. 删除过期的元素后再统计,key中的元素个数(1个小时内的发送次数),看是否大于6次。
  4. 发送成功后,将当前时间戳做为值和分值保存在zset中。

四、代码示例

一个小时内同一用户最多发送6次短信

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations.TypedTuple;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.Set;

import static java.util.stream.Collectors.toList;

@Component
public class RateLimiter {

    private static final String KEY_PREFIX = "rate_limiter:send_msg:";
    private static final long INTERVAL_MS = TimeUnit.HOURS.toMillis(1);
    private static final int MAX_COUNT = 6;

    private final RedisTemplate<String, Object> redisTemplate;

    public RateLimiter(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    public boolean canPerformOperation(String userId) {
        String key = KEY_PREFIX + userId;

        // 获取当前时间戳(毫秒)
        long now = System.currentTimeMillis();

        // 删除已过期的计数
        long startOfInterval = now - INTERVAL_MS;
        Set<TypedTuple<Object>> expiredCounts = redisTemplate.opsForZSet().rangeByScoreWithScores(key, 0, startOfInterval);
        if (!expiredCounts.isEmpty()) {
            List<Object> expiredKeys = expiredCounts.stream().map(TypedTuple::getValue).collect(toList());
            redisTemplate.opsForZSet().removeRangeByScore(key, 0, startOfInterval);
            System.out.println("Removed " + expiredCounts.size() + " expired counts");
        }

        // 获取剩余次数
        long currentCount = redisTemplate.opsForZSet().zCard(key);
        long remainingCount = MAX_COUNT - currentCount;

        // 如果剩余次数大于0,则添加新的计数项并返回true
        if (remainingCount > 0) {
            redisTemplate.opsForZSet().add(key, now, now);
            return true;
        } else {
            return false;
        }
    }

    // 示例用法:
    public static void main(String[] args) {
        RateLimiter rateLimiter = ...; // 初始化RateLimiter实例
        String userId = "100000";
        if (rateLimiter.canPerformOperation( userId )) {
            System.out.println("Sending msg...");
        } else {
            System.out.println("Rate limit exceeded. Unable to send msg.");
        }
    }
}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值