手写SQL,用limit实现分页

分页查询: select from purchase where id = #{id} and category = #{category} limit #{offset}, #{pageSize};

总页数查询:select count(1) from (select from purchase where id = #{id} and category = #{category}) t1;

PurchaseMapper mapper = sqlSession.getMapper(PurchaseMapper.class);
QueryCondition condition = new QueryCondition();
condition.setPageNum(pageNum);
condition.setPageSize(pageSize);
System.out.println(new PageVO<>(pageSize, pageNum, mapper.count(condition), mapper.findPageByHand(condition));

RowBounds分页

使用RowBounds对象后,就不需要在SQL语句中写limit语句了,但是仍然要对满足条件的数据条数进行单独查询,其结果将用于计算总页数。

PurchaseMapper mapper = sqlSession.getMapper(PurchaseMapper.class);
QueryCondition condition = new QueryCondition();
System.out.println(new PageVO<>(pageSize, pageNum, mapper.count(condition),
	mapper.findAllPage(condition, new RowBounds((pageNum - 1)*pageSize, pageSize))));

RowBounds分页是将所有的数据查询到内存中以后,再使用RowBounds参数进行分页的(具体是通过游标),所以对内存的压力很大,性能很低,因此这种方式不建议使用

分页插件 Pagehelper

使用拦截器拦截SQL语句的执行,并为SQL语句添加limit关键字进行分页查询,以及count语句来查询总数

PurchaseMapper mapper = sqlSession.getMapper(PurchaseMapper.class);
QueryCondition condition = new QueryCondition();
Page page = pageHelper.startPage(pageNum, pageSize);
List<Purchase> purchaseList = mapper.findByCondition(condition);
System.out.println(new PageVO<>(pageSize, pageNum, (int)page.getTotal(), purchaseList));

原理:

Executor接口的query方法进行了拦截。

在创建Executor时,如果有插件对Executor进行拦截,则会对Executor对象生成代理,在执行相对应的方法时进行增强处理。

@Override
public Object intercept(Invocation invocation) throws Throwable {
    try {
        ...
        //调用方法判断是否需要进行分页,如果不需要,直接返回结果
        if (!dialect.skip(ms, parameter, rowBounds)) {
            //判断是否需要进行count查询
            if (dialect.beforeCount(ms, parameter, rowBounds)) {
                //查询总数
                Long count = count(executor, ms, parameter, rowBounds, null, boundSql);
                //处理查询总数,返回true时继续分页查询,false时直接返回
                if (!dialect.afterCount(count, parameter, rowBounds)) {
                    //当查询总数为0时,直接返回空的结果
                    return dialect.afterPage(new ArrayList(), parameter, rowBounds);
                }
            }
            resultList = ExecutorUtil.pageQuery(dialect, executor,
                    ms, parameter, rowBounds, resultHandler, boundSql, cacheKey);
        } else {
            //rowBounds有参数值,不使用分页插件处理时,仍然支持默认的内存分页
            resultList = executor.query(ms, parameter, rowBounds, resultHandler, cacheKey, boundSql);
        }
        // 将查询结果设置到Page对象中
        return dialect.afterPage(resultList, parameter, rowBounds);
    } finally {
        if(dialect != null){
            dialect.afterAll();
        }
    }
}