MyBatis好好学五(PageHelper插件和自定义插件)

MyBatis好好学五(PageHelper插件和自定义插件)

大纲

  • 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())。
end
  • 作者:旭仔(联系作者)
  • 发表时间:2024-03-10 20:39
  • 版权声明:自由转载-非商用-非衍生-保持署名
  • 转载声明:如果是转载栈主转载的文章,请附上原文链接
  • 公众号转载:请在文末添加作者公众号二维码(公众号二维码见右边,欢迎关注)
  • 评论