【视频&交流平台】
http://study.163.com/course/introduction.htm?courseId=1004329008&utm_campaign=commission&utm_source=400000000155061&utm_medium=share
http://study.163.com/course/introduction.htm?courseId=1004638001&utm_campaign=commission&utm_source=400000000155061&utm_medium=share
https://gitee.com/happyangellxq520/spring-boot
http://412887952-qq-com.iteye.com/blog/2321532
关注spring boot微信公众号,第一时间了解最新的spring boot动态,当前已经更新到:《184. Spring Boot 2.0终于正式发布》 、《185.Spring Boot使用FastJson解析JSON数据:中文乱码》
需求缘起:
在之前的文章中我们介绍了mybatis的自定义插件以及原理,我们最终的目的是要分析下分页插件的原理。
一、PageHelper是如何在mybatis中工作
PageHelper是如何在mybatis中工作呢,是通过mybatis的pulgin实现了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对象,在这个对象中有我们设置的pageNum、pageSize,也会查询返回的pages、total。
好了,就说这么多吧,更深入的东西还需要靠自己去摸索。
关注spring boot微信公众号,第一时间了解最新的spring boot动态,当前已经更新到:《185. Spring Boot 2.0终于正式发布》
———— 微信公众号 ————
提供Spring Boot资讯、技术文章,具体关注方式:
搜索springboot或者扫描以下二维码即可关注