目录
工作中常会遇到连续多次向Redis插入数据的场景,这时候要是使用for循环一条条的插入,效率低下不说,还显得low,不符合我们的B格,这时候就可以用到本文中所说的方法了
一、通过Pipeline(管道)批量插入
使用redisTemplate.executePipelined重写RedisCallback的doInRedis方法
RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
redisTemplate.executePipelined(new RedisCallback<Object>() {
@Override
public Object doInRedis(RedisConnection redisConnection) throws DataAccessException {
map.forEach((key,value) -> {
redisConnection.set(serializer.serialize("pipeline"+key),serializer.serialize(String.valueOf(value)),
Expiration.seconds(600), RedisStringCommands.SetOption.UPSERT);
});
return null;
}
},serializer);
为什么在doInRedis方法中返回null呢?我们点进去executePipelined()方法的源码中可看到,若不为null就抛出异常
Object result = action.doInRedis(connection);
if (result != null) {
throw new InvalidDataAccessApiUsageException("Callback cannot return a non-null value as
it gets overwritten by the pipeline");
}
二、使用multiSet批量插入
效率最高,缺点是不能设置过期时间
redisTemplate.opsForValue().multiSet(map);
三、效率测试
本文使用三种方法插入五万条数据进行对比测试
@RestController
@RequestMapping("/testRedis")
@Slf4j
public class TestRedisController {
@Resource
private RedisTemplate<String ,Object> redisTemplate;
private static Map<String, Object> map = new HashMap<>();
@PostConstruct
public void initMap(){
for (int i = 0; i < 50000; i++) {
map.put(i+"",i);
}
log.info("Map数据初始化完成,现有:{}",map.size());
}
@GetMapping("/testBatchInsert")
@ApiOperation("批量插入")
public ResultVO<Object> testBatchInsert(){
// 常规循环插入
long s2 = System.currentTimeMillis();
map.forEach((key,value)->{
redisTemplate.opsForValue().set("common"+key,value,10, TimeUnit.MINUTES);
});
long e2 = System.currentTimeMillis();
log.info("常规循环插入耗时:{}",e2-s2);
// 管道插入
long start = System.currentTimeMillis();
RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
redisTemplate.executePipelined(new RedisCallback<Object>() {
@Override
public Object doInRedis(RedisConnection redisConnection) throws DataAccessException {
map.forEach((key,value) -> {
redisConnection.set(serializer.serialize("pipeline"+key),serializer.serialize(String.valueOf(value)),
Expiration.seconds(600), RedisStringCommands.SetOption.UPSERT);
});
return null;
}
},serializer);
long end = System.currentTimeMillis();
log.info("管道批量插入耗时:{}",end-start);
// 批量插入
long s3 = System.currentTimeMillis();
redisTemplate.opsForValue().multiSet(map);
long e3 = System.currentTimeMillis();
log.info("批量插入耗时:{}",e3-s3);
return ResultUtils.success();
}
}
执行两次结果如下:
四、小结
从测试结果可看出,使用multiSet()方式速度最快,管道次之,循环最慢;但multiSet最致命的就是无法设置过期时间,如果业务允许的话使用此方式最好;要根据实际的业务场景来选择使用哪种方式
欢迎大家指正错误,转载请注明出处!