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.

使用 RedisTemplate 执行 SCAN 命令进行批量删除操作的步骤如下: 1. 首先,创建一个 RedisTemplate 对象,用于执行 Redis 命令操作。可以通过注入或者手动创建 RedisTemplate 对象。 2. 使用 RedisTemplate 的 execute 方法执行 SCAN 命令,该命令可以遍历 Redis 中的所有 key。 3. 在 SCAN 命令的回调函数中,可以对每个 key 进行判断和处理。如果符合删除条件,则可以使用 RedisTemplate 的 delete 方法删除该 key。 下面是一个示例代码: ```java @Autowired private RedisTemplate<String, Object> redisTemplate; public void batchDeleteByScan(String pattern) { ScanOptions options = ScanOptions.scanOptions().match(pattern).count(1000).build(); redisTemplate.executeWithStickyConnection((RedisCallback<Void>) connection -> { Cursor<byte[]> cursor = connection.scan(options); while (cursor.hasNext()) { byte[] keyBytes = cursor.next(); String key = new String(keyBytes, StandardCharsets.UTF_8); // 判断是否符合删除条件,这里以示例为准 if (key.startsWith("prefix")) { redisTemplate.delete(key); } } cursor.close(); return null; }); } ``` 在上述示例中,我们使用了 `executeWithStickyConnection` 方法来确保在 SCAN 命令执行期间使用同一个连接。这是因为 SCAN 命令可能需要多次执行才能遍历完所有的 key,而每次执行 SCAN 命令时都需要使用同一个连接。 请注意,上述示例中的 `pattern` 参数是用来匹配需要删除的 key 的模式,可以使用通配符进行模糊匹配。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值