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