redis 使用redisTemplate使用PipeLine方式 利用lRange 批量获取队列内容并移除当前获取的消息

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());

感谢前辈

https://cloud.tencent.com/developer/article/1554080.

你可能感兴趣的:(redis,缓存,java)