首先, 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传递的参数。