上次看到一個問題:如何用Redis實現只允許一個用戶一天內登錄五次。
想到Redis中可以給string設置過期時間,所以我們可以利用這個特性來實現。
作爲一個java程序猿,我們使用Jedis,具體使用到的API是:
/**
* The command is exactly equivalent to the following group of commands:
* {@link #set(String, String) SET} + {@link #expire(String, int) EXPIRE}. The operation is atomic.
*/
public String setex(final String key, final int seconds, final String value) {
checkIsInMultiOrPipeline();
client.setex(key, seconds, value);
return client.getStatusCodeReply();
}
具體的代碼如下:package com.test.redis.test;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Set;
import org.junit.Test;
import redis.clients.jedis.Jedis;
//By John 2018-04-02
public class TestRedis002 {
private final static int TIME_LIMIT = 24; //一個週期,這裏爲了測試方便,我將週期設置的比較小
private static Jedis jedis;
private static int next = 0; //爲了避免key相互覆蓋,我們加上一個自增後綴,使得key不會一樣
private final static int MOST_TIMES_IN_TIME_LIMIT = 5; //一個週期內最多的操作次數
private final static String SEPERATOR = "~~"; //爲了爲了避免next後綴和原來的key互相影響,加上一個分隔字符串
static{
jedis = new Jedis("127.0.0.1", 6379);
}
private boolean login(String username, String password){
if ( ! simpleValidation(username) || ! simpleValidation(password)) return false; //進行一下簡單的格式攔截
System.out.println(getCurTimeAsStr()); //當前操作時間
Set<String> keys = jedis.keys(username + "*"); //爲了搜索出當前操作用戶的週期內(也就是沒有過期的)記錄
if (keys != null && keys.size() >= MOST_TIMES_IN_TIME_LIMIT) {
//週期內的操作次數爲容許次數
System.out.println(TIME_LIMIT + " 秒內只能操作" + MOST_TIMES_IN_TIME_LIMIT + " 次");
return false;
}
/**
* 生成一個包含有操作用戶標識的唯一key
* 每次操作的next都會自增1,防止key相同
*/
String strengthenStr = username + SEPERATOR + (next ++ );
jedis.setex(strengthenStr, TIME_LIMIT, password); //給key設置過期時間
System.out.println(strengthenStr + " 操作成功");
return true;
}
private boolean simpleValidation(String test){
return test != null && test.length() > 5;
}
private String getCurTimeAsStr(){
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
}
}
以及測試代碼:
@Test
public void test() throws InterruptedException{
String username = "username123";
String password = "password234";
login(username, password);
login(username, password);
login(username, password);
login(username, password);
login(username, password);
login(username, password);
login(username, password);
Thread.sleep((TIME_LIMIT + 2) * 1000); // 過了一個週期之後再次進行測試
login(username, password);
}
測試結果:2018-04-02 22:16:21
username123~~0 操作成功
2018-04-02 22:16:21
username123~~1 操作成功
2018-04-02 22:16:21
username123~~2 操作成功
2018-04-02 22:16:21
username123~~3 操作成功
2018-04-02 22:16:21
username123~~4 操作成功
2018-04-02 22:16:21
24 秒內只能操作5 次
2018-04-02 22:16:21
24 秒內只能操作5 次
2018-04-02 22:16:47
username123~~5 操作成功
由測試結果可知,前面5次都成功了,隨後的兩次都因爲在一個週期之內,所以沒有成功。一個週期之後,至少第一次存在緩存數據庫中的key已經過期了(實際上經過26秒後,前面五次的都已經過期了),這就給最後一次操作騰出了空間,所以最後一次也成功了。