Mybatis 分页插件的使用

714 阅读7分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第21天,点击查看活动详情

一、分页插件

  MyBatis 通过提供插件机制,让我们可以根据自己的需要去增强MyBatis 的功能。需要注意的是,如果没有完全理解MyBatis 的运行原理和插件的工作方式,最好不要使用插件,因为它会改变系底层的工作逻辑,给系统带来很大的影响。

  MyBatis 的插件可以在不修改原来的代码的情况下,通过拦截的方式,改变四大核心对象的行为,比如处理参数,处理SQL,处理结果。

四大核心对象的行为有:

  • Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
  • ParameterHandler (getParameterObject, setParameters)-负责设置/获取参数
  • ResultSetHandler (handleResultSets, handleOutputParameters)-负责接收结果集
  • StatementHandler (prepare, parameterize, batch, update, query)-负责执行具体增删查改

  这些类中方法的细节可以通过查看每个方法的签名来发现,或者直接查看 MyBatis 发行包中的源代码。 如果你想做的不仅仅是监控方法的调用,那么你最好相当了解要重写的方法的行为。 因为在试图修改或重写已有方法的行为时,很可能会破坏 MyBatis 的核心模块。 这些都是更底层的类和方法,所以使用插件的时候要特别当心。

  通过 MyBatis 提供的强大机制,使用插件是非常简单的,只需实现 Interceptor 接口,并指定想要拦截的方法签名即可。

二、Mybatis插件典型适用场景

2-1、分页功能

mybatis的分页默认是基于内存分页的(查出所有,再截取),数据量大的情况下效率较低,不过使用mybatis插件可以改变该行为,只需要拦截StatementHandler类的prepare方法,改变要执行的SQL语句为分页语句即可;

2-2、公共字段统一赋值

一般业务系统都会有创建者,创建时间,修改者,修改时间四个字段,对于这四个字段的赋值,实际上可以在DAO层统一拦截处理,可以用mybatis插件拦截Executor类的update方法,对相关参数进行统一赋值即可;

2-3、性能监控

对于SQL语句执行的性能监控,可以通过拦截Executor类的update, query等方法,用日志记录每个方法执行的时间;

2-4、其它

其实mybatis扩展性还是很强的,基于插件机制,基本上可以控制SQL执行的各个阶段,如执行阶段,参数处理阶段,语法构建阶段,结果集处理阶段,具体可以根据项目业务来实现对应业务逻辑。

三、分页插件的使用

3-1、查找分页插件

首先打开gitHub网站,然后搜索mybatis-pagehelper

image.png

找到对应的项目 image.png 选择中文文档

image.png

使用maven,添加依赖

image.png 选择版本

image.png

最终添加的依赖为

image.png

3-2、配置拦截器分页插件

image.png

项目设置如下(相关配置参数先不设置,后面再介绍)

image.png

3-3、在代码中使用分页插件

可以先看下官方提供的示例,有六种,推荐第二、第三种。

image.png

3-4、实际使用

3-4-1、在Mapper.xml中创建查询方法

image.png

3-4-2、测试分页

只需要在执行查询前加上上面提到的使用代码即可

image.png 如上图,sql已经自动加上limit,并且返回的数据有page对象,其中包括一些分页常用到的属性,比如总条数/总页码等。

3-4-2-1、使用PageInfo获得更加详细的信息

官方给我们提供了PageInfo的分页对象,里面包括了更加详细的分页数据,如下:

image.png 具体参数如下:

/**
 * 当前页
 */
private int pageNum;
/**
 * 每页的数量
 */
private              int      pageSize;
/**
 * 当前页的数量
 */
private              int      size;

/**
 * 由于startRow和endRow不常用,这里说个具体的用法
 * 可以在页面中"显示startRow到endRow 共size条数据"
 * 当前页面第一个元素在数据库中的行号
 */
private long startRow;
/**
 * 当前页面最后一个元素在数据库中的行号
 */
private long endRow;
/**
 * 总页数
 */
private int pages;
/**
 * 前一页
 */
private int prePage;
/**
 * 下一页
 */
private int nextPage;

/**
 * 是否为第一页
 */
private boolean isFirstPage = false;
/**
 * 是否为最后一页
 */
private boolean isLastPage = false;
/**
 * 是否有前一页
 */
private boolean hasPreviousPage = false;
/**
 * 是否有下一页
 */
private boolean hasNextPage = false;

/**
 * 导航页码数
 */
private int navigatePages;
/**
 * 所有导航页号
 */
private int[] navigatepageNums;
/**
 * 导航条上的第一页
 */
private int navigateFirstPage;
/**
 * 导航条上的最后一页
 */
private int navigateLastPage;
3-4-2-1-1、使用PageInfo测试

image.png

3-4-2-1-2、PageInfo的核心属性

如下,通过以下参数,我们就可以对前端的分页显示进行相关控制了。 image.png

3-4-2-1-3、修改PageInfo页码导航

image.png

3-5、分页属性的解析

下面几个参数都是针对默认 dialect 情况下的参数。使用自定义 dialect 实现时,下面的参数没有任何作用。

  1. helperDialect:分页插件会自动检测当前的数据库链接,自动选择合适的分页方式。 你可以配置helperDialect属性来指定分页插件使用哪种方言。配置时,可以使用下面的缩写值:
    oracle,mysql,mariadb,sqlite,hsqldb,postgresql,db2,sqlserver,informix,h2,sqlserver2012,derby
    特别注意: 使用 SqlServer2012 数据库时,需要手动指定为 sqlserver2012,否则会使用 SqlServer2005 的方式进行分页。
    你也可以实现 AbstractHelperDialect,然后配置该属性为实现类的全限定名称即可使用自定义的实现方法。

    一般不用设置,数据库会自动

  2. offsetAsPageNum:默认值为 false,该参数对使用 RowBounds 作为分页参数时有效。 当该参数设置为 true 时,会将 RowBounds 中的 offset 参数当成 pageNum 使用,可以用页码和页面大小两个参数进行分页。

  3. rowBoundsWithCount:默认值为false,该参数对使用 RowBounds 作为分页参数时有效。 当该参数设置为true时,使用 RowBounds 分页会进行 count 查询。

  4. pageSizeZero:默认值为 false,当该参数设置为 true 时,如果 pageSize=0 或者 RowBounds.limit = 0 就会查询出全部的结果(相当于没有执行分页查询,但是返回结果仍然是 Page 类型)。

  5. reasonable:分页合理化参数,默认值为false。当该参数设置为 true 时,pageNum<=0 时会查询第一页, pageNum>pages(超过总数时),会查询最后一页。默认false 时,直接根据参数进行查询。

  6. params:为了支持startPage(Object params)方法,增加了该参数来配置参数映射,用于从对象中根据属性名取值, 可以配置 pageNum,pageSize,count,pageSizeZero,reasonable,不配置映射的用默认值, 默认值为pageNum=pageNum;pageSize=pageSize;count=countSql;reasonable=reasonable;pageSizeZero=pageSizeZero

  7. supportMethodsArguments:支持通过 Mapper 接口参数来传递分页参数,默认值false,分页插件会从查询方法的参数值中,自动根据上面 params 配置的字段中取值,查找到合适的值时就会自动分页。 使用方法可以参考测试代码中的 com.github.pagehelper.test.basic 包下的 ArgumentsMapTest 和 ArgumentsObjTest

  8. autoRuntimeDialect:默认值为 false。设置为 true 时,允许在运行时根据多数据源自动识别对应方言的分页 (不支持自动选择sqlserver2012,只能使用sqlserver),用法和注意事项参考下面的场景五

  9. closeConn:默认值为 true。当使用运行时动态数据源或没有设置 helperDialect 属性自动获取数据库类型时,会自动获取一个数据库连接, 通过该属性来设置是否关闭获取的这个连接,默认true关闭,设置为 false 后,不会关闭获取的连接,这个参数的设置要根据自己选择的数据源来决定。

  10. aggregateFunctions(5.1.5+):默认为所有常见数据库的聚合函数,允许手动添加聚合函数(影响行数),所有以聚合函数开头的函数,在进行 count 转换时,会套一层。其他函数和列会被替换为 count(0),其中count列可以自己配置。

重要提示:

当 offsetAsPageNum=false 的时候,由于 PageNum 问题,RowBounds查询的时候 reasonable 会强制为 false。使用 PageHelper.startPage 方法不受影响。