大纲
-
pageHelper插件
-
自定义插件
1、pageHelper插件
1、pageHelper的作用
PageHelper是MyBatis中非常方便的第三方分页插件。
注意:springboot的版本和pagehelp的版本不匹配的化,会存在循环依赖问题导致启动失败。
-- 引入依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.2.10</version>
</dependency>
代码示例:
@Override
public PageInfo<TsCompareDetailLog> getCompareDetailPage(Long fundId, Integer businessDate, Integer pageNo, Integer pageSize) {
if (pageNo == null || pageSize == null) {
pageNo = PAGE_NO_DEFAULT;
pageSize = PAGE_SIZE_DEFAULT;
}
TsCompareDetailLogCriteria tsCompareDetailLogCriteria = new TsCompareDetailLogCriteria();
TsCompareDetailLogCriteria.Criteria criteria = tsCompareDetailLogCriteria.createCriteria();
if (businessDate != null) {
criteria.andBusinessDateEqualTo(businessDate);
}
if (fundId != null) {
criteria.andFundIdEqualTo(fundId);
}
PageHelper.startPage(pageNo, pageSize);
return new PageInfo<>(tsCompareDetailLogMapper.selectByExample(tsCompareDetailLogCriteria));
}
2、PageHelper 的特点
PageHelper 的特点主要有以下几点:
-- 无侵入性
使用 PageHelper 对 MyBatis 进行分页处理时,不需要修改原有的 SQL 语句,也不需要修改 Mapper 接口和 XML 文件。
-- 易用性
使用 PageHelper 只需要在项目中引入相关依赖,然后通过代码或配置即可实现分页功能。
-- 强大的功能
PageHelper 支持多种数据库,支持复杂的分页查询功能,例如排序、聚合查询、连表查询等。
-- 高度自定义
PageHelper 支持自定义拦截器,并且提供了丰富的配置选项,可以根据实际需要进行自定义设置
3、实现原理
主要是通过拦截器(Interceptor)来实现。在 MyBatis 中,提供了 Interceptor 接口用于对 SQL 语句进行拦截和处理,PageHelper 就是实现了这个接口,从而实现了对 SQL 语句的拦截和分页处理
2、自定义插件
Mybatis仅可以编写针对ParameterHandler、ResultSetHandler、StatementHandler、Executor这4种接口的插件,Mybatis使用JDK的动态代理,为需要拦截的接口生成代理对象以实现接口方法拦截功能,每当执行这4种接口对象的方法时,就会进入拦截方法,具体就是InvocationHandler的invoke()方法,当然,只会拦截那些你指定需要拦截的方法。
编写插件:实现Mybatis的Interceptor接口并复写intercept()方法,然后再给插件编写注解,指定要拦截哪一个接口的哪些方法即可,最后在配置文件中配置你编写的插件。
1、MyBatis核心对象介绍
MyBatis的主要的核心部件有以下几个:
// 1、Configuration
Configuration 初始化基础配置,比如MyBatis的别名等,一些重要的类型对象,如,插件,映射器,
ObjectFactory和typeHandler对象,MyBatis所有的配置信息都维持在Configuration对象之中
// 2、SqlSessionFactory
SqlSession工厂
// 3、SqlSession
SqlSession 作为MyBatis工作的主要顶层API,表示和数据库交互的会话,完成必要数据库增删改查功能
// 4、Executor
MyBatis执行器,是MyBatis 调度的核心,负责SQL语句的生成和查询缓存的维护
// 5、StatementHandler
封装了JDBC Statement操作,负责对JDBC statement 的操作,如设置参数、将Statement结果集转换成List集合。
// 6、ParameterHandler
负责对用户传递的参数转换成JDBC Statement 所需要的参数,
// 7、ResultSetHandler
负责将JDBC返回的ResultSet结果集对象转换成List类型的集合;
// 8、TypeHandler
负责java数据类型和jdbc数据类型之间的映射和转换
// 9、MappedStatement
MappedStatement维护了一条<select|update|delete|insert>节点的封装
// 10、SqlSource
负责根据用户传递的parameterObject,动态地生成SQL语句,将信息封装到BoundSql对象中,并返回
// 11、BoundSql
表示动态生成的SQL语句以及相应的参数信息
2、Mybatis执行图
3、MyBatis 拦截器步骤流程
Mybatis支持对Executor、StatementHandler、PameterHandler和ResultSetHandler 接口进行拦截,也就是说会对这4种对象进行代理 主要有两种不同的形式构建configuration并添加拦截器interceptor 第一种:通过SqlSessionFactoryBean去构建Configuration添加拦截器并构建获取SqlSessionFactory。 第二种:通过原始的XMLConfigBuilder 构建configuration添加拦截器,这里主要是解析配置文件的plugin节点,根据配置的interceptor 属性实例化Interceptor 对象,然后添加到Configuration 对象中的InterceptorChain 属性中。 定义了拦截器链,初始化配置文件的时候就把所有的拦截器添加到拦截器链中,mybatis 在实例化Executor、ParameterHandler、ResultSetHandler、StatementHandler四大接口对象的时候调用interceptorChain.pluginAll() 方法插入进去的。其实就是循环执行拦截器链所有的拦截器的plugin() 方法,mybatis官方推荐的plugin方法是Plugin.wrap() 方法,这个类就TargetProxy类
- 自定义拦截器步骤和解析
拦截对象 | 拦截对象作用 | 拦截方法 |
---|---|---|
Executor | 拦截执行器的方法 | update, query, flushStatements, commit, rollback,getTransaction, close, isClosed |
ParameterHandler | 拦截参数的处理 | getParameterObject, setParameters |
ResultHandler | 拦截结果集的处理 | prepare, parameterize, batch, update, query |
StatementHandler | 拦截Sql语法构建的处理 | handleResultSets, handleOutputParameters |
- 拦截器类注解
@Intercepts({@Signature(
type = '' ,
method = "",
args = {}
)})
// 参数说明
@Intercepts:标识该类是一个拦截器;
@Signature:指明自定义拦截器需要拦截哪一个类型,哪一个方法;
type:上述四种类型中的一种;
method:对应接口中的哪类方法(因为可能存在重载方法);
args:对应哪一个方法的入参;
Intercepts注解需要一个Signature(拦截点)参数数组。通过Signature来指定拦截哪个对象里面的哪个方法。@Intercepts注解定义如下:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Intercepts {
/**
* 定义拦截点
* 只有符合拦截点的条件才会进入到拦截器
*/
Signature[] value();
}
Signature来指定咱们需要拦截那个类对象的哪个方法。定义如下:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({})
public @interface Signature {
/**
* 定义拦截的类 Executor、ParameterHandler、StatementHandler、ResultSetHandler当中的一个
*/
Class<?> type();
/**
* 在定义拦截类的基础之上,在定义拦截的方法
*/
String method();
/**
* 在定义拦截方法的基础之上在定义拦截的方法对应的参数,
* JAVA里面方法可能重载,故注意参数的类型和顺序
*/
Class<?>[] args();
}
标识拦截注解@Intercepts规则使用,简单实例如下:
@Intercepts({//注意看这个大花括号,也就这说这里可以定义多个@Signature对多个地方拦截,都用这个拦截器
@Signature(
type = ResultSetHandler.class,
method = "handleResultSets",
args = {Statement.class}),
@Signature(type = Executor.class,
method = "query",
args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
})
自定义注解类实现org.apache.ibatis.plugin.Interceptor接口,重写以下方法:
public class MybatisPageIntercepter implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
return null;
}
@Override
public Object plugin(Object o) {
return null;
}
@Override
public void setProperties(Properties properties) {
}
}
拦截器通过实现Mybatis提供的Interceptor拦截接口,重写了三个方法:setProperties/plugin/ intercept,三者执行顺序是setProperties—》plugin—》Interceptor。
// setProperties方法:
该方法通过设置属性,将核心配置文件configuration.xml文件中对拦截器的配置项下的属性获取过来,便于在拦截器中使用。
// plugin方法:
该方法用来协商,达成协议,把代理权给普通的业务员this,传进wrap方法实现的源码去做代理,没有获取代理权的代理人在这个地方就会停下,不会向下走了,获取代理权的代理人可以去做拦截代理。
// intercept方法:
则是获取拦截对象下的要拦截的东西,然后对其加以改编,添加自己的行为,按照条件进行改编拦截对象,然后通过源码下的反射invocation来调用被拦截的方法,让原本被拦截的方法继续执行(invocation.proceed())。
评论