mybatis分页
Mybatis使用分页
对这块的了解不是那么深,所以在这里需要来做一个详细的说明。了解背后的原理,来总结一下这里的东西,我觉得非常有用。
我们可以查询出来所有的数据,但是页面上肯定不会直接展示出来一页数据,所以需要来进行分页查询。
关于分页查询,点击页面的时候,首先肯定是先有“无条件”查询,然后再有根据页面上的选择框来进行有条件查询的。无条件查询是没有用户输入的参数;有条件查询是有用户输入的参数;
所以这里可以总结出来,肯定是有一个对应的实体类来进行封装的。对应的类:
public class QueryPageBean implements Serializable{
private Integer currentPage;//页码
private Integer pageSize;//每页记录数
private String queryString;//查询条件
// getter/setter
}
这里的搜索框比较简单,用的就是一个string类型的参数,当然也可以写一个实体类来进行封装。
“无条件”查询和有条件查询,对于无条件查询来说,首先应该具备的两个参数,currentPage和pageSize这两个参数是默认的。当然也可以来写死,也是可以的。无非就是多了一个条件而已。
使用post方式:因为传递的是多个参数,需要来进行@RequestBody来进行封装条件
那么后台需要做的事情是:根据条件查询出来的总数据,最终也需要在页面上来进行显示。那么应该有总条数+条件查询记录
至于分页的事情,应该交给前端来做。
分页请求参数:currentPage+pageSize (无条件查询),currentPage+pageSize +queryString (有条件查询) QueryPageBean类
分页响应结果:total(条件查询的总记录数)+rows(条件查询当前页面需要显示的数据集合) PageResult类
但是最终都需要通过Result类来响应出去,分页的操作交给PageHelper分页插件来操作;
PageHelper插件使用:
1、引入分页插件;
2、配置分页插件;
3、在Service层中使用:
a.
PageHelper.startPage(1,10);
b.需要来写分页查询的语句(SQL语句中不必写limit关键字)
c.在ab两步中间不要写任何的代码。返回结果对象Page
d.从page对象中获取得到total、rows的值。
正确使用方式:
接口层:
//分页查询
@RequestMapping("findPage")
public PageResult findPage(@RequestBody QueryPageBean queryPageBean){
PageResult pageResult = checkItemService.pageQuery(
queryPageBean.getCurrentPage(),
queryPageBean.getPageSize(),
queryPageBean.getQueryString());
return pageResult;
}
service层:
@Override
public PageResult pageQuery(Integer currentPage, Integer pageSize, String queryString) {
PageHelper.startPage(currentPage,pageSize);
Page<CheckItem> page = checkItemDao.selectByCondition(queryString);
return new PageResult(page.getTotal(),page.getResult());
}
dao:
Page<CheckItem> selectByCondition( String queryString);
对应的xml文件:
<select id="selectByCondition" parameterType="string" resultType="com.itheima.pojo.CheckItem">
select * from t_checkitem
<if test="condition != null and condition.length > 0">
where code = #{value} or name = #{value}
</if>
</select>
那么重点分析一下servcie层的两条语句:
PageHelper.startPage(currentPage,pageSize);
Page<CheckItem> page = checkItemDao.selectByCondition(queryString);
看一下startPage中的方法,最终会来到com.github.pagehelper.PageHelper
public class PageHelper implements Interceptor
public static <E> Page<E> startPage(int pageNum, int pageSize, boolean count, Boolean reasonable, Boolean pageSizeZero) {
Page<E> page = new Page(pageNum, pageSize, count);
page.setReasonable(reasonable);
page.setPageSizeZero(pageSizeZero);
Page<E> oldPage = SqlUtil.getLocalPage();
if (oldPage != null && oldPage.isOrderByOnly()) {
page.setOrderBy(oldPage.getOrderBy());
}
// 来到了这里!!
SqlUtil.setLocalPage(page);
return page;
}
看一下具体的实现:
private static final ThreadLocal<Page> LOCAL_PAGE = new ThreadLocal<Page>();
public static void setLocalPage(Page page) {
LOCAL_PAGE.set(page);
}
可以看到这里使用ThreadLocal类来进行修饰的,所以这里应该会有get和remove方法来进行调用,在当前类中可以看到:
public static void clearLocalPage() {
LOCAL_PAGE.remove();
}
public static <T> Page<T> getLocalPage() {
return LOCAL_PAGE.get();
}
那么为什么需要下面两个语句在一起使用?
PageHelper.startPage(currentPage,pageSize);
Page<CheckItem> page = checkItemDao.selectByCondition(queryString);
不妨从clearLocalPage这个方法来入手,因为执行完selectByCondition应该会立刻执行clearLocalPage操作。
如果中间有对应的SQL查询语句,那么将会使得查询的时候,不会来拼接limit ?,?来进行拼接了,因为上一条SQL语句执行完成之后会将ThreadLocal中的数据给清除掉。
不妨用案例来进行演示一下:
@Override
public PageResult pageQuery(Integer currentPage, Integer pageSize, String queryString) {
PageHelper.startPage(currentPage,pageSize);
System.out.println("hello,world");
Page<CheckItem> page = checkItemDao.selectByCondition(queryString);
return new PageResult(page.getTotal(),page.getResult());
}
如上操作,添加输出语句!分页操作不受任何影响。
接着测试:
@Override
public PageResult pageQuery(Integer currentPage, Integer pageSize, String queryString) {
PageHelper.startPage(currentPage,pageSize);
List<CheckItem> checkItemList = checkItemDao.findAll();
Page<CheckItem> page = checkItemDao.selectByCondition(queryString);
return new PageResult(page.getTotal(),page.getResult());
}
这里就有了问题!因为findAll这条SQL执行完成之后,会将ThreadLocal中的变量给清除掉,导致后面的找不到对应的线程变量
可以看到selectByCondition的方法执行,会来进行获取,但是没有获取得到,那么就会去查询所有的语句!