PageHelper原理及使用

目录

 

Mybatis原理

PageHelper使用

添加依赖

加入插件

使用

分析

总结


Mybatis原理

 

                              

PageHelper使用

添加依赖

<!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper -->
<dependency>
   <groupId>com.github.pagehelper</groupId>
   <artifactId>pagehelper</artifactId>
   <version>5.1.6</version>
</dependency>

 

加入插件

在springboot项目中的配置类这样写

public SqlSessionFactory sqlSessionFactoryBean() {
    SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
    bean.setDataSource(dataSource);
    //分页插件
    PageInterceptor pageInterceptor = new PageInterceptor();
    Properties properties = new Properties();
    properties.setProperty("reasonable", "true");
    properties.setProperty("supportMethodsArguments", "true");
    properties.setProperty("returnPageInfo", "check");
    properties.setProperty("params", "count=countSql");
    pageInterceptor.setProperties(properties);

    //添加插件
    bean.setPlugins(new Interceptor[]{pageInterceptor});

    //添加XML目录
    ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
    try {
        bean.setMapperLocations(resolver.getResources("../../..*.xml"));
        return bean.getObject();
    } catch (Exception e) {
        e.printStackTrace();
        throw new RuntimeException(e);
    }
}

使用

PageHelper.startPage(pageNum, pageSize);
List<Model> list = ServiceImpl.method(..args);
PageInfo<Model> pageInfo = new PageInfo<Model>(list);
PageHelper.clearPage();
return pageInfo;

分析

我们首先看到配置类中配置SqlSessionFactory 的时候,调用添加插件的方法,添加了一个拦截器链。

添加的是这样一个拦截器

@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}),
        }
)

我们可以看到拦截的是Executer,拦截的方法是query,就是查询方法,拦截它干啥?

 

我们看一下mybatis生产sqlsession的时候发生了什么?

这里创建了一个executor,进入查看。

发现是拦截器链的其中一个方法返回的,这个拦截器链中包含我们在配置类中加入的拦截器,进入查看。

发现返回的结果是每个拦截器的plugin方法处理一遍的executor,再次我们只关心PageHelper的拦截器作用的结果,那么看PageInterceptor中的plugin方法做了什么。

这个Plugin是mybatis中的类,PageInterceptor调用这个方法,要把自己作为参数生产一个执行器的包装类。

这是执行代码

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  try {
    Set<Method> methods = signatureMap.get(method.getDeclaringClass());
    // 如果是定义的拦截的方法 就执行intercept方法
    if (methods != null && methods.contains(method)) {
        // 进入查看 该方法增强
      return interceptor.intercept(new Invocation(target, method, args));
    }
    // 不是需要拦截的方法 直接执行
    return method.invoke(target, args);
  } catch (Exception e) {
    throw ExceptionUtil.unwrapThrowable(e);
  }
}

那对于查询方法,我们知道执行方法的时候,执行的是intercept,那执行的过程是什么样子的呢?

我们debug进去看详细过程。

以上是设置了分页之后,会走的路径,在intercept()方法中。

此时,还未拼接sql语句,进入函数,这个函数取分页参数并设置分页参数。

为什么会有分页参数呢?进入函数。

发现是从ThreadLocal中获取的。

我们在查询之前有这么一行代码

PageHelper.startPage(pageNum, pageSize);

它具体操作如下,发现我们设置的参数封装到了page中,然后加入到了ThreadLocal中。

然后继续,到返回的时候进入这个函数。

往下走可以看到

进入函数一直跟踪,发现

在这里拼接了分页语句。

于是最后执行的其实是拼接之后的语句,占位符的数据即分页参数,作为参数传了进去。

 

总结

跟其它Mybatis Plugin一样,我们需要在Mybatis的配置文件或配置类中注册需要使用的Plugin,PageHelper5.0版本中对应的Plugin实现类就是com.github.pagehelper.PageInterceptor。Mybatis的Plugin我们说是Plugin,实际上对应的却是org.apache.ibatis.plugin.Interceptor接口,因为Interceptor的核心是其中的plugin(Object target)方法,而对于plugin(Object target)方法的实现,我们在需要对对应的对象进行拦截时会通过org.apache.ibatis.plugin.Plugin的静态方法wrap(Object target, Interceptor interceptor)返回一个代理对象,而方法入参就是当前的Interceptor实现类。

PageHelper拦截的是org.apache.ibatis.executor.Executor的query方法,其传参的核心原理是通过ThreadLocal进行的。当我们需要对某个查询进行分页查询时,我们可以在调用Mapper进行查询前调用一次PageHelper.startPage(..),这样PageHelper会把分页信息存入一个ThreadLocal变量中。在拦截到Executor的query方法执行时会从对应的ThreadLocal中获取分页信息,获取到了,则进行分页处理。

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值