`

183. Spring Boot MyBatis分页插件原理

阅读更多

 

 

关注spring boot微信公众号,第一时间了解最新的spring boot动态,当前已经更新到:184. Spring Boot 2.0终于正式发布 、185.Spring Boot使用FastJson解析JSON数据:中文乱码

 

需求缘起:

       在之前的文章中我们介绍了mybatis的自定义插件以及原理,我们最终的目的是要分析下分页插件的原理。

一、PageHelper是如何在mybatis中工作

PageHelper是如何在mybatis中工作呢,是通过mybatispulgin实现了Interceptor接口。这个部分在之前的文章中花了不少篇幅进行介绍了,PageHelper也不另外,如下源码(版本:pagehelper-4.2.1):

 

 @SuppressWarnings("rawtypes")
@Intercepts(@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}))
public class PageHelper extends BasePageHelper implements Interceptor {
    private final SqlUtil sqlUtil = new SqlUtil();
 
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        return sqlUtil.intercept(invocation);
    }
 
    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }
 
    @Override
    public void setProperties(Properties properties) {
        sqlUtil.setProperties(properties);
    }
}

 

 

这里就不过多在进行阐述。这里PageHelper有一个地方就是如何进行分页参数的传递的。

 

二、PageHelper使用原理

PageHelper会使用ThreadLocal获取到同一线程中的变量信息,各个线程之间的Threadlocal不会相互干扰,也就是Thread1中的ThreadLocal1之后获取到Tread1中的变量的信息,不会获取到Thread2中的信息所以在多线程环境下,各个Threadlocal之间相互隔离,可以实现,不同thread使用不同的数据源或不同的Thread中执行不同的SQL语句,所以,PageHelper利用这一点通过拦截器获取到同一线程中的预编译好的SQL语句之后将SQL语句包装成具有分页功能的SQL语句,并将其再次赋值给下一步操作,所以实际执行的SQL语句就是有了分页功能的SQL语句。看源码:

       找到startPage代码:

public static <E> Page<E> startPage(int pageNum, int pageSize) {
        return startPage(pageNum, pageSize, true);
}

 

       最终是执行到代码:

    public static <E> Page<E> startPage(int pageNum, int pageSize, boolean count, Boolean reasonable, Boolean pageSizeZero) {
        Page<E> page = new Page<E>(pageNum, pageSize, count);
        page.setReasonable(reasonable);
        page.setPageSizeZero(pageSizeZero);
        //当已经执行过orderBy的时候
        Page<E> oldPage = SqlUtil.getLocalPage();
        if (oldPage != null && oldPage.isOrderByOnly()) {
            page.setOrderBy(oldPage.getOrderBy());
        }
        SqlUtil.setLocalPage(page);
        return page;
    }

 

       这里有定义了一个Page对象,如下源码:

 

public class Page<E> extends ArrayList<E> {
    private static final long serialVersionUID = 1L;

    /**
     * 页码,从1开始
     */
    private int pageNum;
    /**
     * 页面大小
     */
    private int pageSize;
    /**
     * 起始行
     */
    private int startRow;
    /**
     * 末行
     */
    private int endRow;
    /**
     * 总数
     */
    private long total;
    /**
     * 总页数
     */
private int pages;
//摘取部分源码…
}

 

       这里重要的代码:SqlUtil.setLocalPage(page)

    public static void setLocalPage(Page page) {
        LOCAL_PAGE.set(page);
    }

 

       那么LOCAL_PAGE是什么呢?

protected static final ThreadLocal<Page> LOCAL_PAGE = new ThreadLocal<Page>();

 

       所以PageHelper就是使用ThreadLocal存储了Page对象,在这个对象中有我们设置的pageNumpageSize,也会查询返回的pagestotal

       好了,就说这么多吧,更深入的东西还需要靠自己去摸索。

 

 

关注spring boot微信公众号,第一时间了解最新的spring boot动态,当前已经更新到:185. Spring Boot 2.0终于正式发布

 

————  微信公众号 ————

提供Spring Boot资讯、技术文章,具体关注方式:

搜索springboot或者扫描以下二维码即可关注


 

à悟空学院:https://t.cn/Rg3fKJD

学院中有Spring Boot相关的课程!点击「阅读原文」进行查看!

SpringBoot视频:http://t.cn/A6ZagYTi

Spring Cloud视频:http://t.cn/A6ZagxSR

SpringBoot Shiro视频:http://t.cn/A6Zag7IV

SpringBoot交流平台:https://t.cn/R3QDhU0

SpringData和JPA视频:http://t.cn/A6Zad1OH

SpringSecurity5.0视频:http://t.cn/A6ZadMBe

Sharding-JDBC分库分表实战http://t.cn/A6ZarrqS

分布式事务解决方案「手写代码」:http://t.cn/A6ZaBnIr

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics