为什么PageHelper能实现分页?

本文介绍了在遇到分页查询问题时,通过分析PageHelper源码,揭示了其如何通过设置Page对象到ThreadLocal中并利用MyBatis的拦截器机制,在执行查询时动态添加分页条件,实现分页功能。
摘要由CSDN通过智能技术生成

今天处理分页查询时,报PersistenceException。查看控制台发现,sql中没有获取到分页参数,而且多了一个用来查询总数queryUpfile_Count方法。

在这里插入图片描述
反复确认了传参无问题后,最后查看xml发现sql语句有拼接limit #{pageNo}, #{pageSize}。这时候我就想,原有项目中使用PageHelper做分页,是不是凭借的sql语句与PageHelper产生冲突呢?带着这个疑问我就来查看PageHelper的源码。

<!-- 查询上传文件记录 -->
<select id="queryUpfile" resultType="IotMsisdnUpfile">
  select <include refid="Base_Column_List"/>
  from iot_msisdn_upfile
  limit #{pageNo}, #{pageSize}; 
</select>

一般情况下我们使用PageHelper时,都会先使用startPage(),后面紧跟着一个查询语句,进而开始分页功能。

PageHelper.startPage(pageNo, pageSize);
List<IotMsisdnUpfile> list = iotMsisdnUpfileMapper.queryUpfile(pageNo, pageSize);

我们使用debug模式进入PageMethod中的startPage方法,一路往下点来到如下面所示的方法。发现我们传递pageNo和pageSize保存到Page中,并设置到setLocalPage(page)方法中。

/**
 * 开始分页
 *
 * @param pageNum      页码
 * @param pageSize     每页显示数量
 * @param count        是否进行count查询
 * @param reasonable   分页合理化,null时用默认配置
 * @param pageSizeZero true且pageSize=0时返回全部结果,false时分页,null时用默认配置
 */
public static <E> Page<E> startPage(int pageNum, int pageSize, boolean count, Boolean reasonable, Boolean pageSizeZero) {
   
    Page<E> page = new Page<E>(pageNum, pageSize, count);
    page.setReasonable(reasonable);
    page.setPageSizeZero(pageSizeZero);
    //当已经执行过orderBy的时候
    Page<E> oldPage = getLocalPage();
    if (oldPage != null && oldPage.isOrderByOnly()) {
   
        page.setOrderBy(oldPage.getOrderBy());
    }
    setLocalPage(page);
    return page;
}

点开setLocalPage()之后,恍然大悟,原来page保存到ThreadLocal中,用来保证变量的线程私有,确认线程安全问题。

protected static final ThreadLocal<Page> LOCAL_PAGE = new ThreadLocal<Page>();

/**
 * 设置 Page 参数
 *
 * @param page
 */
protected static void setLocalPage(Page page) {
   
    LOCAL_PAGE.set(page);
}

我们知道,ThreadLoacal中有set(),必然有get()。这时候我们就猜想MyBatis中肯定使用了get()方法获取到Page对象,并取出我们传入pageNo和pageSize,从而实现分页查询。
我们继续往下面debug,来到MapperProxy中的invoke()方法,并且执行了execute()方法。

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
   
    try {
   
        if (Object.class.equals(method.getDeclaringClass())) {
   
            return method.invoke(this, args);
        } else if (isDefaultMethod(method)) {
   
            return invokeDefaultMethod(proxy, method, args);
        }
    } catch (
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值