使用分页从 Redis 缓存中检索数据

Retrieve data from redis cache with pagination

我有结构如下的redis缓存

private HashOperations<String, Long, Object> hashOperations;
//put data in cache
hashOperations.put("Key", 1, SomeObject);

我需要使用分页从缓存中获取数据(第一页 50 个结果,第二页下 50 个结果,依此类推)。如何使用 spring 数据 redis 来实现。感谢任何帮助。

如果你需要保证元素的顺序,我认为你需要某种排序集(HSCAN 是读取整个哈希的好方法,但它不能保证它的顺序returns 并且不保证其中没有重复数据 returns)。唯一符合有序集描述的 Redis 数据类型是:ZSETZSETs 具有类似于 HASHes 的字段,但是,在它们的字段中,它们有一个 double "score",而不是字符串值,用于对字段进行排序。

因此,要获得 "hash paging",您可以做的一件事是让 ZSET 具有与您的 HASH 所有相同的字段。 HASH 将包含您字段中的数据,ZSET 将跟踪它们的顺序。

ZSETs 有一个名为 ZRANGE (documentation) 的方法,它允许您从集合中获取特定数量的元素。对于大小为 50 的 "page",它看起来像这样:

# this gets you the "page" with the first 50 elements
ZRANGE 0 50

# this gets you the "page" with the second 50 elements
ZRANGE 50 100

# etc.

因此,要向 zset/hash 添加一些数据然后获取页面,您可以执行以下操作(伪代码 - 可能无法编译):

RedisTemplate<String, String> redisTemplate;

String myKey = "exampleKey";

// example of adding one record to the HASH + ZSET
String myField = "field1";
String myData = "123ABC";

// in this example data inserted into the ZSET is ordered based on when it was inserted.
// if you want to order it differently you can figure out your own way of coming up with scores
redisTemplate.opsForZSet().add(myKey + "zset", myField, System.getCurrentTimeMillis());
redisTemplate.opsForHash.put(mykey + "hash", myField, myData);

// Get one page from the hash
Set<String> first50hashFields = redisTemplate.opsForZSet().range(myKey + "zset", 0, 50);

List<String> firstPage = LinkedList<>();
for (String hashFieldKey : first50hashFields) {
     String hashFieldValue = redisTemplate.opsForHash().get(myKey + "hash", hashFieldKey);

     firstPage.add(hashFieldValue);
}

希望全字符串示例足以说明如何做到这一点。

我在网上找到了一些变通方法并使用了相同的方法。

@Override
    public List<Entity> findAll(final int pageNum, final int pageSize) {
        // Please validate the pageNum and pageSize in Controller that should be positive numbers
        int tmpIndex = 0;
        int tmpEndIndex = 0;
        final List<Entity> entities = new ArrayList<>();
        try (Cursor<Entry<Object, Object>> cursor = redisTemplate.opsForHash().scan(CACHE_KEY,
                ScanOptions.scanOptions().match("*").build())) {
            while (cursor.hasNext()) {
                if (tmpIndex >= pageNum && tmpEndIndex < pageSize) {
                    final Entry<Object, Object> entry = cursor.next();
                    final Entity entity = (Entity) entry.getValue();
                    entities.add(entity);
                    tmpIndex++;
                    tmpEndIndex++;
                    continue;
                }
                if (tmpEndIndex >= pageSize) {
                    break;
                }
                tmpIndex++;
                cursor.next();
            }
        } catch (Exception ex) {
            if (LOGGER.isInfoEnabled()) {
                LOGGER.info("Exception while fetching data from redis cache : " + ex);
            }
        }
        return entities;
    }