一,概述
MyBatis的分頁使用的關鍵字就是limit,插件分頁的原理就是在sql語句中拼接limit關鍵字,進行數據的分頁查詢,所以pageHelper也不例外,底層處理的就是使用的代理對象拼接的Sql,實現的分頁。其實思想都離不開原始的分頁的sql語句,雖然這樣的分頁插件好用,但是建議初學者最好不要使用,如果要使用,也要吃透底層的原理才可以加深理解, 否則的話,可能只會使用不能明白其中的原理。
pageHelper使用的是ThreadLocal本地線程變量的特性來進行存儲分頁的的部分數據,使用到分頁查詢的參數組裝,而且在使用一次后,就會被remove,但是這個是必須的,一個是防止分頁數據被其他sql誤用,一個是防止內存泄露。使用的是mybatis的實現Interceptor接口,使用jdk動態代理的模式,增強Executor對象,實現的代理對象,組裝count和limit分頁數據的查詢的sql語句,返回一個page對象,page對象其實就是繼承了list對象,所以返回的List對象是父類,適應多態。
二,原理分析設置分頁數據PageHelper.startPage(重寫startPage)
封裝分頁的pageNum pageSize以及orderFiled的一些數據
public static Page startPage(int pageNum, int pageSize, String orderBy) {Page page = startPage(pageNum, pageSize);page.setOrderBy(orderBy);return page;public static Page startPage(int pageNum, int pageSize, Boolean count, Boolean reasonable, Boolean pageSizeZero) {Page page = new Page(pageNum, pageSize, count);page.setReasonable(reasonable);page.setPageSizeZero(pageSizeZero);Page oldPage = getLocalPage();if (oldPage != null && oldPage.isOrderByOnly()) {page.setOrderBy(oldPage.getOrderBy());//設置分頁的數據存放在ThreadLocal里面,setLocalPage(page);return page;
以上是可以看出,分頁的數據是和ThreadLocal綁定的,也是將數據存放在ThreadLocal里面,提供給后續分頁的時候使用
清除ThreadLocal分頁數據
以上圖你可以看出,清除數據的是在com.github.pagehelper.PageInterceptor#intercept方法中的finally中執行的,概述也說過,其實執行的原理就是利用的mybatis的intercept的進行的對象的代理
Pageinterceptor代理的源頭
@Intercepts注解就是標注需要攔截代理的對象,type就是對象為Executor,方法是query,參數為兩個重載的方法,PageInterceptor實現Interceptor并實現intercept和plugin方法,進行數據代理的處理,setProperties方法其實是可以設置配置參數來處理,實現接口原因是因為mybatis使用的jdk動態代理,必須是實現接口的才可以創建代理對象,下面就intercept方法進行分析分頁的處理邏輯
intercept方法
this.count進行查詢統計總數
就是使用原sql語句進行count查詢總數
com.github.pagehelper.util.ExecutorUtil#pageQuery
dialect.getPageSql就是拼接sql語句中的limit
看到這里,可能就可以明白了,這個分頁到底是怎么做的 了,其實就是sql拼接了limit,總上圖就可以看出,規歸根結底就是代理了Excutor對象,然后執行count和拼接limit的sql語句,實現的插件的分頁
小結
以上可以看出來,其實就是一個Excutor代理對象的一系列處理,簡單而言,pageHelper的分頁邏輯處理,可以就這么理解,其實就是生成代理對象并代理增強,從ThreadLocal中獲取到分頁的參數,拼接sql和查詢總數的sql并返回一個page對象
三,Excutor邏輯補充
首先寫分頁插件的話,需要知道mybatis的原理,執行Sql的是四大對象:Executor,StatementHandler,ParameterHandler,ResultSetHandler。
一般都會獲取SqlSession,獲取途徑一般都是SqlSessionFactory .openSession
Executor的創建
增強對象
從上面可以看出,其實Executor創建的過程就是執行了攔截器inteceptor中的攔截器鏈