一、前言
最近在做一个业务,场景是这样的:用户批量导入数据,程序需要把导入数据与现有数据库对比,解析成(新增/变更/异常)三个数据,因为用户还需要对这些数据进行部分的修改/删除,因此当时的方案是把数据存放到redis里面,在最后用户确认变更提交的时候再从redis拿数据存到数据库。这三个数据要分开展示,又由于每一项的数据量都很大,因此要做一个分页展示。
二、设计方案
为了做分页,考虑使用有序的集合来存储数据,选择了zSet数据结构,使用score来从1开始记录每一项的序号,再通过用户传进来的pageSize
和pageNum
来计算应该取哪个范围的数据。
项目使用的是Springboot,使用redisTemplate
来操作。
三、示例代码
3.1 分页获取Redis数据代码
1 | /** |
2 | * 分页查询zset数据,zset的数据score需要是从1开始递增 |
3 | * |
4 | * @param key |
5 | * @param pageNum |
6 | * @param pageSize |
7 | * @return |
8 | */ |
9 | public Set zSetGetByPage(String key, int pageNum, int pageSize) { |
10 | try { |
11 | if (redisTemplate.hasKey(key)) { |
12 | int start = (pageNum - 1) * pageSize; |
13 | int end = pageNum * pageSize - 1; |
14 | Long size = redisTemplate.opsForZSet().size(key); |
15 | if (end > size) { |
16 | end = -1; |
17 | } |
18 | return redisTemplate.opsForZSet().range(key, start, end); |
19 | } else { |
20 | return null; |
21 | } |
22 | } catch (Exception e) { |
23 | e.printStackTrace(); |
24 | return null; |
25 | } |
26 | } |
3.2 将数据存到Redis
这里需要注意的是,将每一个对象存到zSet的时候,必须设置score,并且score需要从1开始。
1 | Map addCompCacheMap = new HashMap<Integer, String>(); |
2 | for (int i = 0; i < addCompList.size(); i++) { |
3 | AddDataCacheVo addDataCacheVo = new AddDataCacheVo(); |
4 | CompanyImportVo companyImportVo = addCompList.get(i); |
5 | BeanUtils.copyProperties(companyImportVo, addDataCacheVo); |
6 | addDataCacheVo.setKey(userNo + "-add-importData"); |
7 | addDataCacheVo.setScore((i + 1) + ""); |
8 | addCompCacheMap.put(i + 1, JSON.toJSONString(addDataCacheVo)); |
9 | } |
10 | LOG.info("开始写入新增数据缓存"); |
11 | if (addCompCacheMap.size() > 0) { |
12 | redisUtil.executePipelined(userNo + "-add-importData", addCompCacheMap); |
13 | } |
14 | LOG.info("完成写入新增数据缓存"); |