MyBatis|MyBatis 最佳实践篇 1(分页)

1 默认分页(逻辑分页)
MyBatis 默认提供了分页功能,即 RowBounds 类,该类提供两个参数:offset 和 limit。offset 为起始行数,limit 为要查询的行数。

public class RowBounds { //other... public static final int NO_ROW_OFFSET = 0; public static final int NO_ROW_LIMIT = Integer.MAX_VALUE; private final int offset; private final int limit; public RowBounds() { this.offset = NO_ROW_OFFSET; this.limit = NO_ROW_LIMIT; }public RowBounds(int offset, int limit) { this.offset = offset; this.limit = limit; } //other... }

但使用 RowBounds 的默认分页是逻辑分页:从数据库一次性查询出所有的记录,再通过传入的 RowBounds 的 offset 和 limit 的值,使用 for 循环进行过滤。源码如下:
org.apache.ibatis.executor.resultset.DefaultResultSetHandler 类:
private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException { DefaultResultContext resultContext = new DefaultResultContext(); skipRows(rsw.getResultSet(), rowBounds); while (shouldProcessMoreRows(resultContext, rowBounds) && rsw.getResultSet().next()) { ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(rsw.getResultSet(), resultMap, null); Object rowValue = https://www.it610.com/article/getRowValue(rsw, discriminatedResultMap); storeObject(resultHandler, resultContext, rowValue, parentMapping, rsw.getResultSet()); } }
private void skipRows(ResultSet rs, RowBounds rowBounds) throws SQLException { if (rs.getType() != ResultSet.TYPE_FORWARD_ONLY) { if (rowBounds.getOffset() != RowBounds.NO_ROW_OFFSET) { rs.absolute(rowBounds.getOffset()); } } else { for (int i = 0; i < rowBounds.getOffset(); i++) { rs.next(); } } }

为了验证上面的逻辑,我们执行下面的测试方法:
public void testDefaultPaging() { SqlSession session = FactoryBuildByXML.getFactory().openSession(true); try { RowBounds rowBounds = new RowBounds(2, 11); List list = session.selectList("com.zhaoxueer.learn.dao.AuthorMapper.selectAllTest", null, rowBounds); System.out.println("查询的结果数:" + list.size()); } finally { session.close(); } }
AuthorMapper 中 selectAllTest 方法为:
@Select("select id, name, sex, phone from author") List selectAllTest();

执行结果为:
DEBUG [main] - ==>Preparing: select id, name, sex, phone from author DEBUG [main] - ==> Parameters: 查询的结果数:11

这种分页方式不能满足我们对于减轻数据库压力的要求,因此不建议使用。
2 使用 pagehelper 插件(物理分页)
为了简单地实现真正的物理分页,我们可以使用插件去实现,网上有很多这样的插件,例如比较常用的 pagehelper 插件。
只需要简单的三步:
  • 第一步:maven 引入依赖:
com.github.pagehelper pagehelper latest version

注:修改 version 为最新的版本号(如 5.1.7),可点击上面链接查看最新版本。
  • 第二步:mybatis-config.xml 注册该 plugin:

  • 第三步:代码中使用:
public void testPageHelper() { SqlSession session = FactoryBuildByXML.getFactory().openSession(true); try { AuthorMapper authorMapper = session.getMapper(AuthorMapper.class); // 只需要在查询语句前插入该语句即可实现分页 PageHelper.startPage(1, 10); List authorList = authorMapper.selectAllTest(); System.out.println("查询的结果数:" + authorList.size()); } finally { session.close(); } }

执行结果为:
DEBUG [main] - ==>Preparing: SELECT count(0) FROM author DEBUG [main] - ==> Parameters: DEBUG [main] - <==Total: 1 DEBUG [main] - ==>Preparing: select id, name, sex, phone from author LIMIT ? DEBUG [main] - ==> Parameters: 10(Integer) DEBUG [main] - <==Total: 10 查询的结果数:10

注意:注入分页插件 plugin 元素后,执行前面默认分页举例中的方法,也会实现物理分页,因为该插件对该方法也进行了拦截处理。
pagehelper 插件的 PageInterceptor 类对以下方法进行拦截:
@Intercepts( { @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}), @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}), } )

【MyBatis|MyBatis 最佳实践篇 1(分页)】默认分页举例中的语句:
RowBounds rowBounds = new RowBounds(2, 11); List list = session.selectList("com.zhaoxueer.learn.dao.AuthorMapper.selectAllTest", null, rowBounds);
对上面两行代码的执行结果为:
DEBUG [main] - ==>Preparing: select id, name, sex, phone from author LIMIT ?, ? DEBUG [main] - ==> Parameters: 2(Integer), 11(Integer) DEBUG [main] - <==Total: 11 查询的结果数:11

因此,若要测试默认分页的逻辑分页方式,请注释掉 plugin 代码块。
更多使用方法查看:MyBatis PageHelper 文档
附: 当前版本:mybatis-3.5.0
官网文档:MyBatis
项目实践:MyBatis Learn
手写源码:MyBatis 简易实现

    推荐阅读