首先, PageHelper的使用, 很簡單,導入依賴,寫幾行簡單的代碼。
<!--MyBatis分頁插件starter--> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>${pagehelper-starter.version}</version> </dependency>
//獲取第1頁,10條內容,默認查詢總數count
PageHelper.startPage(1, 10);
//緊跟着的第一個select方法會被分頁
List<Country> list = userDAO.find();
接下來我們瞭解下PageHelper如何實現分佈的。
首先我們考慮兩個問題。
1) 從上面的代碼看, userDAO.find完成沒有使用到PageHelper相關的參數,那它如何實現分頁的?
答案就是通過PageHelperAutoConfiguration類,向mybatis中添加了pageHelper的攔截器, 如下:
//com.github.pagehelper.autoconfigure.PageHelperAutoConfiguration
@PostConstruct
public void addPageInterceptor() {
PageInterceptor interceptor = new PageInterceptor();
Properties properties = new Properties();
//先把一般方式配置的屬性放進去
properties.putAll(pageHelperProperties());
//在把特殊配置放進去,由於close-conn 利用上面方式時,屬性名就是 close-conn 而不是 closeConn,所以需要額外的一步
properties.putAll(this.properties.getProperties());
interceptor.setProperties(properties);
for (SqlSessionFactory sqlSessionFactory : sqlSessionFactoryList) {
sqlSessionFactory.getConfiguration().addInterceptor(interceptor);
}
}
2) PageHelper.startPage(1, 10)是靜態函數,如何保證各個線程之間不互相影響?
用synchronize,lock, 這些肯定不行。一定是用ThreadLocal.
考慮到Spring對http的請求的處理機制, 每個請求對應一個處理線程,大家就很容易理解爲什麼用ThreaLocal.
下面看代碼:
public abstract class PageMethod {
protected static final ThreadLocal<Page> LOCAL_PAGE = new ThreadLocal<Page>();
protected static boolean DEFAULT_COUNT = true;
/**
* 設置 Page 參數
*
* @param page
*/
protected static void setLocalPage(Page page) {
LOCAL_PAGE.set(page);
}
...
}
結論:
1)PageHelper通過PageHelperAutoConfiguration類向Mybatis註冊了攔截器,在查詢時候,將分頁信息傳遞給Mybatis框架,你通過mybatis查詢的時候能夠使用分頁查詢。
2) PageHelper通過ThreadLocal保證每個查詢使用的分頁信息就是通過PageHelperg靜態函數startPage傳遞的參數。