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