Redis基础配置
配置解析方式,泛型类自动转换更加方便
private RedisTemplate redisTemplate;
private RedisSerializer<String> keySerializer = new StringRedisSerializer();
private Jackson2JsonRedisSerializer<T> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<T>((Class<T>) Object.class);
//初始化设置格式
public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
this.redisTemplate.setKeySerializer(keySerializer);
this.redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
}
LIST 类型
基础操作
leftPushIfPresent不会自动创建队列
//左边插入
redisTemplate.opsForList().leftPush(key, value)
//批量插入
redisTemplate.opsForList().leftPushAll(key, value)
//存在才插入
redisTemplate.opsForList().leftPushIfPresent(key, value)
//获取第一条并删除
redisTemplate.opsForList().leftPop(key, value)
批量操作
//获取列表指定范围内的元素(start开始位置, 0是开始位置,end 结束位置, -1返回所有)
redisTemplate.opsForList().range(key, start, end)
//将List列表进行剪裁
redisTemplate.opsForList().trim(key, start, end)
为什么要用PipeLine?
当我们想从 Redis 的列表里面获取数据消费的时候,我们一般使用pop
一般的场景pop已经足够,我们现在的场景是,消息队列的消息来自多个服务器端收集,统一上报到国家防沉迷平台,有qps限制。消息队列需要封装到128条在做上报。这里就对获取队列在性能上要求比较高。普通的模式已经无法满足需求。但是redis并没有提供批量获取并删除的命令。
使用range
查看了redis的命令可以使用range 命令进行批量操作,然后使用trim 做裁剪。
但是这里会出现一个问题获取数据与删除数据是两条命令,中间有时间差
connection.lRange(_key, 0, size);
connection.lTrim(_key, size, -1);
使用PipeLine
我们就需要使用 Redis 的pipeline功能。它可以把多条命令放在一个网络请求中发送到服务器,并默认在一个事务中执行这些命令。一个事务是不会被打断的,从事务开始然后执行里面的多个命令到结束的整个过程,可以看做一个原子操作
最终实现批量获取
由于有2个命令操作因此需要注意获取第一个操作的内容操作
最终代码如下
接口代码
public interface CacheRealNameLoginOutService<T> {
List<T> popLoginOutQueueList();
}
实现类代码
@Service
public class CacheRealNameLoginOutServiceImpl<T> implements CacheRealNameLoginOutService<T> {
private RedisTemplate redisTemplate;
private RedisSerializer<String> keySerializer = new StringRedisSerializer();
private Jackson2JsonRedisSerializer<T> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<T>((Class<T>) Object.class);
public void setRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
this.redisTemplate.setKeySerializer(keySerializer);
this.redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
}
public List<T> popLoginOutQueueList() {
int size = 127;
final byte[] _key = keySerializer.serialize(LOGIN_OUT_QUEUE_KEY_Test);
List<List<T>> list = redisTemplate.executePipelined(new RedisCallback<T>() {
@Nullable
@Override
public T doInRedis(RedisConnection connection) throws DataAccessException {
connection.openPipeline();
connection.lRange(_key, 0, size);
connection.lTrim(_key, size, -1);
return null;
}
});
return list.get(0);
}
}
}
调用方式代码
private CacheRealNameLoginOutService<Behaviour> cacheRealNameLoginOutService;
List<Behaviour> queueList = new ArrayList<>();
queueList.addAll(cacheRealNameLoginOutService.popLoginOutQueueList());