使用分页从 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 数据类型是:ZSET
。 ZSET
s 具有类似于 HASH
es 的字段,但是,在它们的字段中,它们有一个 double
"score",而不是字符串值,用于对字段进行排序。
因此,要获得 "hash paging",您可以做的一件事是让 ZSET
具有与您的 HASH
所有相同的字段。 HASH
将包含您字段中的数据,ZSET
将跟踪它们的顺序。
ZSET
s 有一个名为 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;
}
我有结构如下的redis缓存
private HashOperations<String, Long, Object> hashOperations;
//put data in cache
hashOperations.put("Key", 1, SomeObject);
我需要使用分页从缓存中获取数据(第一页 50 个结果,第二页下 50 个结果,依此类推)。如何使用 spring 数据 redis 来实现。感谢任何帮助。
如果你需要保证元素的顺序,我认为你需要某种排序集(HSCAN
是读取整个哈希的好方法,但它不能保证它的顺序returns 并且不保证其中没有重复数据 returns)。唯一符合有序集描述的 Redis 数据类型是:ZSET
。 ZSET
s 具有类似于 HASH
es 的字段,但是,在它们的字段中,它们有一个 double
"score",而不是字符串值,用于对字段进行排序。
因此,要获得 "hash paging",您可以做的一件事是让 ZSET
具有与您的 HASH
所有相同的字段。 HASH
将包含您字段中的数据,ZSET
将跟踪它们的顺序。
ZSET
s 有一个名为 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;
}