redis的处理速度是微秒级别,而网络传输的速度是毫秒级别,远远慢于redis的处理速度。所以在使用redis时,网络速度会成为redis的一个瓶颈,节省网络传输的时间得到的收益会远高于节省命令执行时间的收益。
所以对于批量操作,redis总提供了mset,mget这样的命令。今天要写得是pipeline管道操作,可以把多个命令操作打包成一个pipeline一起发送执行,redis处理完后打包结果返回。
mget和pipeline不同之处:M操作是原子性的,而pipeline不是原子性的,执行时会把命令拆开单个执行。
RedisTemplate使用pipeline
redisTemplate.execute方法
如果不关心接口,可以使用execute方法使用pipeline,需要手动开启Pipeline,手动关闭Pipeline提交,结果不可在回调方法中返回。
redisTemplate.execute(new RedisCallback<Long>() {
@Nullable
@Override
public Long doInRedis(RedisConnection connection) throws DataAccessException {
//手动开启Pipeline
connection.openPipeline();
for (int i = 0; i < 1000000; i++) {
String key = "123" + i;
connection.zCount(key.getBytes(), 0,Integer.MAX_VALUE);
}
//手动关闭Pipeline返回结果
List<Object> result=connection.closePipeline();
return null;
}
});
redisTemplate.executePipelined方法
跟上面方法最主要的区别就是: 可以拿到命令执行后返回结果集
- 1.这里回调方法是redis原生connection执行的,其实就是通过connection.openPipeline()和connection.closePipeline()等操作执行回调方法doInRedis中的代码逻辑。所以connection的返回结果是基本上是byte数组,通常需要反序列化,默认不传Serializer的话使用RedisTemplate设置的Serializer。
- 2.在回调方法doInRedis中最后返回值必须返回为null,因为这个值终会被管道返回值覆盖,否则内部执行时会报错Callback cannot return a non-null value as it gets overwritten by the pipeline
- 3.在回调方法doInRedis中,connection.openPipeline()可以调用,也可以不调用(底层方法会再次调用),但是connection.closePipeline()不能调用,因为调用的时候会直接将结果返回,返回了就没办法对结果进行反序列化。
List<Long> List = redisTemplate.executePipelined(new RedisCallback<Long>() {
@Nullable
@Override
public Long doInRedis(RedisConnection connection) throws DataAccessException {
connection.openPipeline();
for (int i = 0; i < 1000000; i++) {
String key = "123" + i;
connection.zCount(key.getBytes(), 0,Integer.MAX_VALUE);
}
return null;
}
});