概述
这个工具类是基于Springboot的PageHelper依赖的
当我们使用Redis进行分页数据同步时,为了避免每次查询都调用数据库创建新的PageInfo对象,所以我们需要自行封装PageInfo的数据。
使用Redis进行分页数据库的数据同步
问题
为了方便数据的修改而不调用大量资源我们不能将所有数据直接封装进Redis中,因为当我们修改其中一条数据时,如果我们使用的是直接将数据写进Redsi中,那么我们只有将该表的所有数据删除然后重新写入数据,当我们数据量庞大时对Redis的压力与速度都是一种挑战
解决方案
这里我使用了Redis的list指向String的数据结构完成数据的存储,并且对分页进行了实现。
list存的是所有数据的地址,String中存的是实际数据,这样我们就可以通过list中的地址访问到实际数据,也可以直接修改我们想要修改的数据,而不是对所有数据进行修改
分页的问题
问题:因为我们实现了分页所以面临着一个新问题,就是我们分页取数据时和数据库取份分页数据一样我们是靠list中的下标取的,如果我们先访问的是第二页那么Redis的list中第一条数据就是第二页的第一条数据,那么当我们访问第一页的数据时,第一页的数据就会存存储在第二页数据之后,这时候数据就会发生错乱。
解决方案:我们可以先对list进行占位然后进行数据的填充,这样就解决这个问题了
代码
这里以对小区数据的同步为例
public class CommunityServiceImpl implements CommunityService{
@Resource
private StringRedisTemplate stringRedisTemplate;
@Resource
private CommunityMapper communityMapper;
//redis中所有小区主键
private static final String ALLCOMMUNITY = "AllCommunity";
//redis每个小区主键
private static final String COMMUNITY = "CommunityId:";
//分页大小
private static final int SIZE = 2;
//根据页码查询所有小区
@Override
public JsonResult findAllCommunity(int page) {
ValueOperations<String, String> opsForValue = stringRedisTemplate.opsForValue();
ListOperations<String, String> opsForList = stringRedisTemplate.opsForList();
//当前页面第一个元素在数据库中的行号
int begin = SIZE * (page - 1);
//当前页面最后一个元素在数据库中的行号
int end = SIZE * page - 1;
//判断有没有存数据地址的表
boolean flag = stringRedisTemplate.hasKey(ALLCOMMUNITY);
//没有该list表则新建并进行占位
if (!flag) {
List list = list();
for (int i = 0; i < list.size(); i++) {
opsForList.rightPush(ALLCOMMUNITY, "");
}
}
//获取数据,这个是根据下标获取我们当前页需要的数据
List listRange = opsForList.range(ALLCOMMUNITY, begin, end);
//判断listRange是否有数据
flag = false;
for (int i = 0; i < listRange.size(); i++) {
if (listRange.get(i).equals("")) {
flag = true;
break;
}
}
//没数据,添加
if (flag) {
//使用PageHelper对数据封装
PageHelper.startPage(page, SIZE);
List<Community> listPage = list();
final int[] temp = {begin};
listPage.forEach(e -> {
//将数据地址存进list
opsForList.set(ALLCOMMUNITY, temp[0], COMMUNITY + e.getId());
//将数据存进String
opsForValue.set(COMMUNITY + e.getId(), JSONArray.toJSONString(e));
temp[0]++;
});
PageInfo<Community> pageInfo = new PageInfo<>(listPage);
//同样将PageInfo存进Redis中
opsForValue.set("CommunityPage", JSONArray.toJSONString(pageInfo));
return ResultTool.success(pageInfo);
}
//有数据,取
//获得之前存进Redis中的PageInfo对象
PageInfo<Community> pageInfo = JSONArray.parseObject(opsForValue.get("CommunityPage"), PageInfo.class);
//从list->string中取出实际数据
List listCommunity = new ArrayList();
listRange.forEach(e -> {
String value = opsForValue.get(e);
Community community = JSONArray.parseObject(value, Community.class);
listCommunity.add(community);
});
//使用PageInfo工具类对数据重新封装
pageInfo = ChangePageInfo.changePageInfo(pageInfo, listCommunity, page);
//这里我自定义了一个JsonResult和ResultTool对数据进行处理,如果没写这个工具类,正常返回PageInfo对象就可以了
return ResultTool.success(pageInfo);
}
}
PageInfo工具类
下面是使用工具类完成对PageInfo的封装
/**
*基于Redis的数据同步问题的PageInfo的变化
*/
public class ChangePageInfo {
/**
* 查询其他页时PageInfo的变化
* @param pageInfo 从Redis中取出的pageInfo对象
* @param data 当前页的数据库数据,类型为list,长度需要与size一样(最后一页的数据可以小于)
* @param page 当前的页码数
* @return 新的pageInfo对象
*/
public static PageInfo changePageInfo(PageInfo pageInfo, List data,int page){
int begin=pageInfo.getSize()*(page-1);
pageInfo.setList(data);
pageInfo.setSize(data.size());
pageInfo.setPageNum(page);
pageInfo.setPrePage(page-1);
if (pageInfo.getPrePage()==0){
pageInfo.setIsFirstPage(true);
pageInfo.setHasPreviousPage(false);
}else {
pageInfo.setIsFirstPage(false);
pageInfo.setHasPreviousPage(true);
}
if (pageInfo.getPages()==page){
pageInfo.setNextPage(0);
pageInfo.setIsLastPage(true);
pageInfo.setHasNextPage(false);
}else{
pageInfo.setNextPage(page+1);
pageInfo.setIsLastPage(false);
pageInfo.setHasNextPage(true);
}
pageInfo.setStartRow(begin + 1);
pageInfo.setEndRow(begin + data.size());
return pageInfo;
}
/**
* 添加数据对PageInfo的变化
* @param pageInfo 从Redis中取出的PageInfo
* @return 更改后新的PageInfo
*/
public static PageInfo insertDataOfPageInfo(PageInfo pageInfo){
pageInfo.setTotal(pageInfo.getTotal()+1);
//判断添加后是不是本页第一条数据
if ((pageInfo.getTotal()%pageInfo.getSize())==1){
//是的话则新增页码
pageInfo.setPages(pageInfo.getPages()+1);
}
return pageInfo;
}
/**
* 删除数据时对PageInfo的变化
* @param pageInfo 从Redis中取出的PageInfo
* @return 更改后新的PageInfo
*/
public static PageInfo deleteDataOfPageInfo(PageInfo pageInfo){
pageInfo.setTotal(pageInfo.getTotal()-1);
//判断删除前是不是最后一页是不是只有一条数据
if ((pageInfo.getTotal()%pageInfo.getSize())==0){
//是则删除最后一页
if (pageInfo.getPages()!=1){
pageInfo.setPages(pageInfo.getPages()-1);
}
}
return pageInfo;
}
}