今天处理分页查询时,报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 (