Recently write a small demo want to achieve how many seconds in the operation of several interface prompts frequent warnings, first of all you have a train of thought, my train of thought is Baidu to find examples!!

Without further ado, code first

Baidu example:

                                     / / into redis key | increase since less each time
long count = redisTemplate.opsForValue().increment("a".1);
if(count == 3) {/ / into redis key | | Settings key for 15 seconds
    redisTemplate.expire("a".15, TimeUnit.SECONDS)
}
if(count > 3) {// This is the response I encapsulated
    return R.failed(ApiErrorCode.FREQUENTLY.getCode(), "Frequent operation");
}
Copy the code

Set the key to expire in 15 seconds, request again, that is, count from three plus one to four and count == Count > 3 = count > 3 = count > 3 = count > 3 = count > 3 = count > 3 = count > 3

The problem

Such as: I set the key expired within 15 seconds time request 3 times, normally I once three times in the case of 4th instructions will appear frequently, but when I asked 2 times, I stopped for a minute in the request, this just found a problem, that is to say I’m connected to request again in a minute twice will prompt leads to frequent operation, this kind of indirect request experience is very poor! !!!!!

After the need to improve the code

RedisExpired: Encapsulates a class that stores data

/** * function description: used to encapsulate frequent request interface, data stored in redis used in the object **@Author: 魏
 * @Date: 2021/6/18 20:13
 */
@Data
public class RedisExpired {
    // redis key
    private String key;
    // redis value
    private Object value;
    // Set the number of frequent operations
    private Integer frequentlyTimes;
    // Expiration time
    private long ExpiredTime;
    / / state
    private Boolean isFlag;

    public RedisExpired(String key, Integer frequentlyTimes, long expiredTime) {
        this.key = key;
        this.frequentlyTimes = frequentlyTimes; ExpiredTime = expiredTime; }}Copy the code

Concrete implementation method

 public static RedisExpired addRedisExpiredTimes(RedisExpired redisExpired){
    Integer i = (Integer) get(redisExpired.getKey());
    if(i ! =null && i > redisExpired.getFrequentlyTimes()){
            redisExpired.setValue(get(redisExpired.getKey()));
            // Set the expiration time of the key
            redisExpired.setExpiredTime(getExpire(redisExpired.getKey()));
            // Set the state
            redisExpired.setIsFlag(false);
            return redisExpired;
    }
    // redis increments by 1 returns the incremented number and sets the expiration time
    long count = incrBy(redisExpired.getKey(), 1,redisExpired.getExpiredTime());
    // The increment is equal to the setting
    if(count == redisExpired.getFrequentlyTimes() + 1){
        redisExpired.setIsFlag(false);
        return redisExpired;
    }
    redisExpired.setIsFlag(true);
    return redisExpired;

}
Copy the code

Operations done by the Service layer

/** * Add/unfollow operations *@paramAccountId User ID *@paramAttentionId Indicates the attentional ID *@paramFlag Current concern status True Concerned false Not concerned */
@Override
public R<Object> addOrCancellFollow(String accountId, String attentionId, boolean flag) {
    RedisExpired redisExpired = RedisUtil.addRedisExpiredTimes(new RedisExpired(
            StrUtil.format("{} : : {}", AccountUtils.getLoginAccount().getName(), accountId),
            3.15));
    if(! redisExpired.getIsFlag()) {return R.failed(ApiErrorCode.FREQUENTLY.getCode(), StrUtil.format("Frequent operation please {} try again", TimeUtils.formatDateTime(redisExpired.getExpiredTime())));
    }
    if (flag){
        // Add attention
        fansMapper.attentionAccount(accountId,attentionId);
        return R.success(true."Focus on success");
    }
    // Unfollow
    fansMapper.cancelAttentionAccount(accountId,attentionId);
    return R.success(false."Unfollow");
}
Copy the code

The above is just my own encapsulation, the main one being the incrBy() method

 /** * increments (self-increments), negative numbers are self-decrement@param key
 * @return* /
public static Long incrBy(String key, long increment,long time) {
    if(time ! =0){
        Long aLong = MyRedisTemplate.opsForValue().increment(key, increment);
        expire(key, time, TimeUnit.SECONDS);
        return aLong;
    }
    return MyRedisTemplate.opsForValue().increment(key, increment);
}
Copy the code

Resolving indirect requests is to set the expiration time after redis increment.

Specific flow chart

  • The improved code has two changes
    • 1. After reaching the specified number of times, the redis increment method is not carried out and the frequent operation is directly returned.
    • 2. Indirect requests. (Set the cache time of the key each time the redis increment)
  • Finally, the function is to allow how many requests in how many seconds, can request again after the time expires, allow indirect requests.

Idea 1

We can also change, that is, we remove the first change (after the specified number of times without redis increment method, directly return to frequent operation.) If there is no such addition, Redis will continue to request the increase, such as within 15 seconds, 100 times we will give him the next request must wait three minutes, 200 times nine minutes, 500 times we will directly ban the account!!

Idea 2

The AOP way to specify certain requests limit the number of requests within the number of seconds requested, AOP pre-notification to achieve