1-引入分页插件
这里使用maven的方式
<dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>最新版本</version> </dependency> |
---|
2-配置拦截器插件PageInterceptor
新版拦截器是com.github.pagehelper.PageInterceptor
可以在MyBatis.xml中配置拦截器插件,也可以在Spring配置中配置
<plugins> <!-- com.github.pagehelper为PageHelper类所在包名 --> <plugin interceptor="com.github.pagehelper.PageInterceptor"> <!-- 使用下面的方式配置参数,参数可以去官网查询 --> <property name="param1" value="value1"/> </plugin> </plugins> |
---|
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <!-- 注意其他配置 --> <property name="plugins"> <array> <bean class="com.github.pagehelper.PageInterceptor"> <property name="properties"> <!--使用下面的方式配置参数,一行配置一个 --> <value> params=value1 </value> </property> </bean> </array> </property> </bean> |
---|
- 我们的项目采用的是封装MySql配置,所以要在定义SqlSessionFactory的时候进行拦截插件的配置
Interceptor[] interceptors = {new PageInterceptor()}; factoryBean.setPlugins(interceptors); |
---|
3-代码中的使用
// 第一种,RowBounds方式的调用 --------------------------------------------------- List<Country> list = sqlSession.selectList("x.y.selectIf", null, new RowBounds(0, 10)); // 第二种,Mapper接口方式的调用,推荐这种使用方式。--------------------------- PageHelper.startPage(1, 10); List<Country> list = countryMapper.selectIf(1); // 第三种,Mapper接口方式的调用,推荐这种使用方式。--------------------------- PageHelper.offsetPage(1, 10); List<Country> list = countryMapper.selectIf(1); // 第四种,参数方法调用--------------------------------------------------------------- //存在以下 Mapper 接口方法,你不需要在 xml 处理后两个参数 public interface CountryMapper { List<Country> selectByPageNumSize( @Param("user") User user, @Param("pageNum") int pageNum, @Param("pageSize") int pageSize); } // 配置supportMethodsArguments=true // 在代码中直接调用: List<Country> list = countryMapper.selectByPageNumSize(user, 1, 10); // 第五种,参数对象------------------------------------------------------------------- //如果 pageNum 和 pageSize 存在于 User 对象中,只要参数有值,也会被分页 //有如下 User 对象 public class User { // 其他fields // 下面两个参数名和 params 配置的名字一致 private Integer pageNum; private Integer pageSize; } // 存在以下 Mapper 接口方法,你不需要在 xml 处理后两个参数 public interface CountryMapper { List<Country> selectByPageNumSize(User user); } // 当 user 中的 pageNum!= null && pageSize!= null 时,会自动分页 List<Country> list = countryMapper.selectByPageNumSize(user); // 第六种,ISelect 接口方式----------------------------------------------------------- // jdk6,7用法,创建接口 Page<Country> page = PageHelper.startPage(1, 10).doSelectPage(new ISelect() { @Override public void doSelect() { countryMapper.selectGroupBy(); } }); // jdk8 lambda用法 Page<Country> page = PageHelper.startPage(1, 10).doSelectPage(()-> countryMapper.selectGroupBy()); //也可以直接返回PageInfo,注意doSelectPageInfo方法和doSelectPage pageInfo = PageHelper.startPage(1, 10).doSelectPageInfo(new ISelect() { @Override public void doSelect() { countryMapper.selectGroupBy(); } }); // 对应的lambda用法 pageInfo = PageHelper.startPage(1, 10).doSelectPageInfo(() -> countryMapper.selectGroupBy()); // count查询,返回一个查询语句的count数 long total = PageHelper.count(new ISelect() { @Override public void doSelect() { countryMapper.selectLike(country); } }); // lambda total = PageHelper.count(()->countryMapper.selectLike(country)); |
---|
4-原理和注意事项
PageHelper.offsetPage(PAGE_NUM, PAGE_SIZE)实际做的事情是在 ThreadLocal中设置了分页参数,之后在查询执行的时候,获取当线程中的分页参数,执行查询的时候通过拦截器在sql语句中添加分页参数,之后实现分页查询,查询结束后在 finally 语句中清除ThreadLocal中的查询参数
PageInterceptor
最核心的逻辑在 PageInterceptor 中,PageInterceptor 是一个拦截器。
Mybatis四个拦截机会
- Executor
- ParameterHandler
- ResultSetHandler
- StatementHandler
分页插件拦截的是 Executor ,也就是在sql执行的时候
Mybatis插件加载流程
读取配置文件到Congiguration实例
生成全局公用的 SqlSessionTemplate以SqlSessionFactory实例
获取接口的代理对象MapperProxy
执行增删改查方法
那么在configuration.newExecutor()方法会加载拦截链,也就是PageInterceptor。
注意
PageHelper方法使用了静态的ThreadLocal参数,分页参数和线程是绑定的。
只要你可以保证在PageHelper方法调用后紧跟 MyBatis 查询方法,这就是安全的。因为PageHelper在finally代码段中自动清除了ThreadLocal存储的对象。