MyBatis允许我们在其执行过程中对特定的一些方法进行拦截代理,实现一些特定的通用功能,如分页插件或者租户插件,允许进行拦截的类及对应方法基本如下
- Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)
- ParameterHandler (getParameterObject, setParameters)
- ResultSetHandler (handleResultSets, handleOutputParameters)
- StatementHandler (prepare, parameterize, batch, update, query)
这部分可以在源码中找到
1 | // Configuration.java |
要想更好的使用MyBatis的插件功能,首先需要对拦截到的类和方法进行了解,以一次查询为例我们看一下相关流程
Executor: Executor是SqlSession中执行功能使用到的类,如查询时,首先从Configuration或获取MappedStatement(可以认为是对应的mapper.xml中的 SELECT节点信息),之后和具体的参数值一起传递给Executor的query方法使用
1 | // Executor.java |
StatementHandler: Executor具体执行时,默认会使用StatementHandler的prepare对要执行的SQL创建预编译的Statement,之后使用parameterize设置参数
1 | // SimpleExecutor.java |
在StatementHandler执行parameterize,默认会使用ParameterHandler#setParameters来对预编译结果继续进行参数设置
之后再调用StatementHandler#query方法来进行查询,最后使用ResultSetHandler#handleResultSets对查询结果进行处理
分析了流程之后,我们就可以根据自己的需求在指定方法上面进行拦截处理,如我们想要统一在数据库层面设置某一个字段值(如创建人信息),那么就可以拦截Executor#update方法,对其中的参数进行修改赋值
下面我们通过例子来具体使用感受一下
数据准备
首先创建一个表(这里是MySQL自带的表)
1 | CREATE TABLE `employees` ( |
插入一些数据(MySQL自带的数据)
1 | INSERT INTO `employees` (`emp_no`,`birth_date`,`first_name`,`last_name`,`gender`,`hire_date`) VALUES (10001,'1953-09-02','Georgi','Facello','M','1986-06-26'); |
之后可以使用mybatis-generator生成表对应的类及相应的mapper文件
分页插件
这里我们以一个最简单的分页插件功能为例,看一下如何实现使用一个插件
因为分页查询就是涉及查询,所以一般可以拦截Executor的query方法,因为有两个query方法,这里就统一都拦截了
1 | // 需要添加拦截器注解 |
之后在mybatis的配置文件中配置上此插件
1 |
|
这时候就可以使用了
1 |
|
这时候可以看到执行的SQL日志
1 | ==> Preparing: select emp_no, birth_date, first_name, last_name, gender, hire_date from employees limit 2 offset 0 |
对应源代码:https://github.com/zavier/mybatis-plugin-example
这里只是一个示例,分页可以使用PageHelper,或者使用如果使用MyBatis-Plus的话,它也提供了很多的插件可以使用(分页插件、乐观锁插件、多租户插件等),这里我们主要就是了解一下原理,在有需要的时候可以开发自定义的插件