项目亮点之分页设计

分页设计

普通分页

内存分页

内存分页,也叫做逻辑分页。就是从数据库中寻找出所有符合条件的数据记录,然后在逻辑层进行分页操作。

分页请求类

@Data
public class PageReq implements Serializable {
    @NotNull(message = "page 不能为空")
    private Integer pageNum;
    @NotNull(message = "pageSize 不能为空")
    private Integer pageSize;
}

分页响应类

@Data
public class PageResp<T> implements Serializable {
    private List<T> list;
    private Integer totalNum;
    private Integer totalPage;
    private Integer pageNum;
    private Integer pageSize;
}

条件查询类

@Data
public class CommonQueryBean {
    private Integer pageSize;
    private Integer start;
    private String sort;
    private String order;
}

条件查询实现

	<!-- list4Page 分页查询-->
    <select id="list4Page" resultMap="Demo">
        SELECT
        <include refid="Base_Column_List"/>
        from demo
        where 1=1
        <if test="record.id != null">
            and id = #{record.id}
        </if>
        <if test="record.text != null and record.text != ''">
            and text = #{record.text}
        </if>
        <if test="record.createTime != null">
            and create_time = #{record.createTime}
        </if>
        <if test="record.updateTime != null">
            and update_time = #{record.updateTime}
        </if>
        <if test="record.isDeleted != null">
            and is_deleted = #{record.isDeleted}
        </if>
        <if test="record.isEnabled != null">
            and is_enabled = #{record.isEnabled}
        </if>
        <if test="commonQueryParam != null">
            <if test="commonQueryParam.order != null ">
                order by #{commonQueryParam.order}
                <if test="commonQueryParam.sort != null ">#{commonQueryParam.sort}</if>
            </if>
            <if test="commonQueryParam.start != null  and commonQueryParam.pageSize != null">
                limit #{commonQueryParam.start}, #{commonQueryParam.pageSize}
            </if>
        </if>
    </select>

分页逻辑

/**
     * 分页边界处理
     *
     * @param count    总数
     * @param pageSize 分页大小
     * @return int
     * @author 石一歌
     * @date 2022/7/14 17:27
     */
    public static int getPageCount(int count, int pageSize) {
        if (pageSize == 0) {
            return 0;
        } else {
            return count % pageSize == 0 ? count / pageSize : count / pageSize + 1;
        }
    }

    /**
     * 首先将分页请求包装类处理,计算得到记录数start和页面大小pageSize并封装到CommonQueryBean
     * 执行list4Page,条件查询所有信息(条件查询)和条数
     * 调用getPageCount方法,处理当前页和总页数的边界问题,组装结果
     *
     * @param req 分页请求包装
     * @return com.bmw.seed.util.bean.PageResp<com.bmw.seed.model.Demo>
     * @author 石一歌
     * @date 2022/7/14 16:39
     */
    @Override
    public PageResp<Demo> page(PageReq req) {
        int start = (req.getPageNum() - 1) * req.getPageSize();
        Demo param = new Demo();
        CommonQueryBean queryBean = new CommonQueryBean();
        queryBean.setStart(start);
        queryBean.setPageSize(req.getPageSize());

        List<Demo> list = demoDao.list4Page(param, queryBean);
        int count = demoDao.count(param);
        PageResp<Demo> pageResp = new PageResp<>();
        pageResp.setList(list);
        pageResp.setPageNum(getPageCount(start + 1, req.getPageSize()));
        pageResp.setPageSize(req.getPageSize());
        pageResp.setTotalNum(count);
        pageResp.setTotalPage(getPageCount(count, req.getPageSize()));
        return pageResp;
    }

物理分页

物理分页,主要是依靠SQL里的Limit语法实现的。

核心sql

SELECT * from user limit #{start},#{pageSize}

大数据分页优化

当原始数据的量达到一定量级,那么两种分页方式的效率都会比较低。

  • 对于内存分页而言,每次都是取全量数据,上万的数据就需要查询至少几十秒,无法优化。
  • 对于物理分页而言,由于是依赖数据库分页,所以可以利用数据库相关优化手段,提高查询效率。

索引覆盖优化

先用快速的索引覆盖查询查出所需主键,再根据主键查询所需要字段

select * from demo where id > =(select id from demo limit 866613, 1) limit 20
select * from demo a join (select id from product demo 866613, 20) b ON a.ID = b.id

游标分页

使用场景

流式展示的分页场景居多,比如朋友圈,今日头条新闻列表等;

需求特征是分页不会取指定页数据,而只需要取下一页数据即可,一般会分页数据按某个维度或者标识排序,比如时间戳或者连续id。

游标的选择

可区分并且连续的字段,比如时间戳或者id。

游标分页逻辑详解

每次请求的参数都包含一个游标值cursor,用来告诉我们上次分页的最后一条数据位置;我们根据游标值,取之后的size条数据返回即可。

分页请求类

@Data
public class CursorPageReq implements Serializable {
    @NotNull(message = "pageSize 不能为空")
    private Integer pageSize;
    private Long cursor;
}

分页响应类

@Data
public class CursorPageResp<T> implements Serializable {
    private List<T> list;
    private Long cursor;
}

分页逻辑

    @Override
    public CursorPageResp<UserInfo> cursorPage(CursorPageReq req) {
        CursorPageResp<UserInfo> resp = new CursorPageResp<>();
        if(req.getCursor()==null){
            List<UserInfo> totalList = userInfoDao.list(new UserInfo());
            totalList.sort((x,y)->Integer.compare(Math.toIntExact(y.getId()), Math.toIntExact(x.getId())));
            List<UserInfo> resultList = totalList.subList(0, req.getPageSize() - 1);
            resp.setCursor(Long.valueOf(resultList.get(resultList.size()-1).getId()));
            resp.setList(resultList);
            return resp;
        }
        List<UserInfo> list = userInfoDao.list4CursorPage(req);
        if (list.size()>0){
            resp.setList(list);
            resp.setCursor(Long.valueOf(list.get(list.size()-1).getId()));
        }
        return resp;
    }

查询实现

	<select id="list4CursorPage" resultMap="UserInfo">
		SELECT
		<include refid="Base_column_List" />
		from user_info
		<where>
			<if test="req.cursor != null">
				and `id` &lt; #{req.cursor}
			</if>
		</where>
		order by `id` desc
		limit #{req.pagesize}
	</select>
posted @ 2022-07-20 13:33  Faetbwac  阅读(95)  评论(3编辑  收藏  举报