参考:MySql从一窍不通到入门(二)大数据量分页查询方法
对JavaWeb来说,分页是十分常见的一种需求,一般来说数据的项目大于单次可显示的条目,因此当查询时需要对查询得到的结果进行分页显示。
Mybatis被称为半自动化的ORM框架,因为相比hibernate而言,其对SQL操作的屏蔽更加浅层表面,Mybatis将SQL操作提取并容纳于Mapper.xml文件中,新添加的操作需要使用者写出SQL语句,因此对于分页是功能较弱。
MyBatis分页的方法按照SQL的执行方式来分为两种:
1. 内存分页,也就是假分页。本质是查出所有的数据然后根据游标的方式截取需要的记录。如果数据量大,开销大和内存溢出。
2. 物理分页,也就是查询执行的SQL语句为添加分页指令后的语句,这种情况下Mybatis的分页不再是系统的性能瓶颈。
按照实现方式来说,物理分页又可以分为自定义SQL和实现拦截器两种,下面分别介绍内存分页和物理分页的实现方法。
优点:实现简单,不需要添加额外代码
缺点:大数据情况下性能差。
内存分页的实现通过利用自动生成的example类,加入mybatis的RowBounds类,在调用的接口中添加给类的参数,示例代码如下:
@RequestMapping("/itemlist1/{pageNum}")
@ResponseBody
private List getItemBypage1(@PathVariable Integer pageNum){
TbItemExample example = new TbItemExample();
RowBounds rowBounds = new RowBounds(0, 5);
TbItemExample.Criteria criteria = example.createCriteria();
example.setOrderByClause("Id desc");//设置排序方式
return itemMapper.selectByExampleEx(example, rowBounds);
}
此处的selectByExampleEx为自定义方法,与selectByExample一致(传入的RowBounds参数由Mybatis自行处理,不需要在SQL语句中做出反应)。
List selectByExampleEx(TbItemExample example, RowBounds rowBounds);
这样实现的分页在大数据情况下需要查询出所有结果后进行截取,因此性能较差,不常使用。
优点:SQL查询效率优化余地大,使用方便
缺点:要为每一个需要分页特性的类添加代码,工作量大且不灵活
自定义SQL的实现需要在真正执行的SQL语句上修改,使传入的参数中增加分页上下限的功能,本次采用修改Example对象的方法进行
public class TbItemExample {
protected String orderByClause;
protected boolean distinct;
public int start;
public int limit;
public int getStart() { return start;}
public void setStart(int start) { this.start = start;}
public int getLimit() { return limit;}
public void setLimit(int limit) { this.limit = limit;}
...
}
@RequestMapping("/itemlist2/{pageNum}")
@ResponseBody
private List getItemBypage2(@PathVariable Integer pageNum){
TbItemExample example = new TbItemExample();
example.setStart(0);
example.setLimit(5);
example.setOrderByClause("Id desc");//设置排序方式
return itemMapper.selectByExample(example);
}
查询能够达到预期效果:
优点:使用方便,不存在分页上额外的性能瓶颈。
缺点:引入开源库干扰项目的稳定性,性能难以优化。
Mybatis中使用的拦截器可以类比Spring中的AOP概念,通过拦截器获取SQL语句,然后对SQL语句进行修改之后再进行下一步查询,这样的方法使用户使用起来更加简洁清晰,但是也需要注意,这样的话SQL优化就只能依靠封装的开源库的内部实现了(毕竟SQL语句修改的地方被开源库隔离了)。常用的开源库是pageHleper,项目地址: Mybatis_PageHelper插件的使用分为如下的步骤:
com.github.pagehelper
pagehelper
3.7.5
作者是个很勤奋的人,目前已经更新到5.x,本博客中使用了3.7.5无误,其余需要摸索下(5.x之后主类名和参数定义发生变化)。
在Controller中添加代码如下:
@RequestMapping("/itemlist/{pageNum}")
@ResponseBody
private List getItemByPage(@PathVariable Integer pageNum) {
PageHelper.startPage(pageNum,10);
TbItemExample example = new TbItemExample();
List list = itemMapper.selectByExample(example);
return list;
}
其中PageHelper.startPage(pageNum,10);指定下一句执行的SQL具备分页特性(只有紧接着的下一句才有效)。
执行结果发现已经达到了分页的目的: