redisTemplate可以發送一段腳本給redis,來調用redis的接口。
腳本準備
執行redis的腳本。對於腳本的學習可以參考官網的文章:https://redis.io/commands/eval
jar包準備
我們使用redisTemplate,它有發送執行腳本的接口(下面的代碼來自spring-data-redis-1.8.1.RELEASE版本):
public <T> T execute(RedisScript<T> script, RedisSerializer<?> argsSerializer, RedisSerializer<T> resultSerializer, List<K> keys, Object... args) {
return this.scriptExecutor.execute(script, argsSerializer, resultSerializer, keys, args);
}
實例
這裏以執行zrange函數爲例,發送“希望執行zrange”的腳本讓redis去執行。
數據準備
先做個數據準備,在命令行中執行兩個語句來插入數據(注意千萬不要一起粘貼執行哦,分開執行):
zadd test 1 one
zadd test 8 eight
然後用zrange查詢下:
zrange test 0 3
結果:
ceshi:0>zrange test 0 3
1) "one"
2) "eight"
腳本準備
接下來在redis的控制檯執行下腳本:
eval "return redis.call(KEYS[1],KEYS[2],ARGV[1],ARGV[2])ceshi:0>" 2 zrange test 0 3
結果:
ceshi:0>eval "return redis.call(KEYS[1],KEYS[2],ARGV[1],ARGV[2])ceshi:0>" 2 zrange test 0 3
1) "one"
2) "eight"
沒問題,接下來就是java的事情了
java編程
這裏只粘貼重要代碼,至於redisTemplate如何配置創建對象,相信廣大的開發者朋友都會。
@Autowired
private RedisTemplate<String, Object> redisTemplate;
public List<String> pageKeysByZrangeScript(String tableName, Long start, Long end) {
String scriptStr = "return redis.call(KEYS[1],KEYS[2], KEYS[3], KEYS[4])";//這裏用了4個KEYS,不用ARGV了,你可以用。不過用了的話,就注意redisTemplate.execute調用的時候,注意給最後一個參數傳遞argv的數組
List<String> keys = new ArrayList<>();
keys.add("zrange");
keys.add(tableName);
keys.add(start + "");
keys.add(end + "");
RedisSerializer redisSerializer = new StringRedisSerializer();
DefaultRedisScript<ArrayList<String>> defaultRedisScript = new DefaultRedisScript(scriptStr, ArrayList.class);
ArrayList<String> result = redisTemplate.execute(defaultRedisScript, new Jackson2JsonRedisSerializer(ArrayList.class), redisSerializer,
keys, new ArrayList<>());//這裏因爲用的4個KEYS,沒用ARGV,所以傳入一個空的ARGV的List
System.out.println(result);
return result;
}
說明:
1. redisTemplate會將我們定義好的語句發送給redis,執行“”eval“”。
2. 這裏比較麻煩的是:
DefaultRedisScript的創建以及redisTemplate.execute執行的時候傳入的序列化和反序列化實例
2.1 首先,因爲查詢的結果是一堆字符串的列表,因此這列DefaultRedisScript的類型爲List<String>
2.2 然後,execute函數:
2.2.1. 第一個參數是腳本,直接傳入即可。
2.2.2. 第二個參數是我們傳入的數據的序列化器(比如,看上面我的代碼,keys對象不是一個String的list麼),我們轉入的是list,因此用類型爲ArrayList的Jackson2JsonRedisSerializer序列化器
2.2.3. 第三個參數,是redis返回數據的序列化器,因爲我們返回的是一個元素爲String的list,因此這列傳入StringRedisSerializer實例,爲什麼是String而不是list的?原因源碼中是這樣解析的:
protected <T> T deserializeResult(RedisSerializer<T> resultSerializer, Object result) {
if (result instanceof byte[]) {
return resultSerializer == null ? result : resultSerializer.deserialize((byte[])((byte[])result));
} else if (!(result instanceof List)) {
return result;
} else {
List results = new ArrayList();
Iterator var4 = ((List)result).iterator();
while(var4.hasNext()) {
Object obj = var4.next();
results.add(this.deserializeResult(resultSerializer, obj));
}
return results;
}
}
注意看,當Object result不是byte[]並且是List的時候,就會遍歷其中的每一個元素,用序列化器去反序列化每一個元素。因此,我們傳String的序列化器。
2.2.4. 第四個參數,是我們的參數list,注意list中的參數對應 KEYS[1],KEYS[2], KEYS[3], KEYS[4] 的順序。
2.2.5. 第五個參數,這個是腳本執行語法中的ARGV[N]的數據,我們這裏全部當做KEY來傳遞,因此全部寫爲KEYS,ARGV爲空的list(注意不能傳null!看源碼就知道了)。
完成
這樣就完成了基本的一個小例子。
看不懂的同學多半是卡在腳本的語法上了,注意仔細看官網文檔即可,這裏再粘貼出來官網地址:https://redis.io/commands/eval