先说结论,满足以下两点即可触发PageHelper隐式分页:
1、application.properties/application.yml中配置了pagehelper.support-methods-arguments=true
2、自定义查询对象中同时包含pageNum和pageSize属性,且可以转换成数字类型
下面从源码进行分析,为什么在进行MyBatis查询的时候,我明明没有调用PageHelper.startPage方法,但是却自动进行了分页。
1、PageHelperAutoConfiguration 自动配置类
@PostConstruct public void addPageInterceptor() { PageInterceptor interceptor = new PageInterceptor(); Properties properties = new Properties(); properties.putAll(this.pageHelperProperties()); properties.putAll(this.properties.getProperties()); interceptor.setProperties(properties); Iterator var3 = this.sqlSessionFactoryList.iterator(); while(var3.hasNext()) { SqlSessionFactory sqlSessionFactory = (SqlSessionFactory)var3.next(); sqlSessionFactory.getConfiguration().addInterceptor(interceptor); } }
我们从PageHelper的自动配置类入手,在PageHelper的配置类中,会创建一个PageInterceptor拦截器。
2、PageInterceptor 分页拦截器
public Object intercept(Invocation invocation) throws Throwable { try { Object[] args = invocation.getArgs(); MappedStatement ms = (MappedStatement)args[0]; Object parameter = args[1]; RowBounds rowBounds = (RowBounds)args[2]; ResultHandler resultHandler = (ResultHandler)args[3]; Executor executor = (Executor)invocation.getTarget(); CacheKey cacheKey; BoundSql boundSql; if (args.length == 4) { boundSql = ms.getBoundSql(parameter); cacheKey = executor.createCacheKey(ms, parameter, rowBounds, boundSql); } else { cacheKey = (CacheKey)args[4]; boundSql = (BoundSql)args[5]; } this.checkDialectExists(); if (this.dialect instanceof Chain) { boundSql = ((Chain)this.dialect).doBoundSql(Type.ORIGINAL, boundSql, cacheKey); } List resultList; if (!this.dialect.skip(ms, parameter, rowBounds)) { if (this.dialect.beforeCount(ms, parameter, rowBounds)) { Long count = this.count(executor, ms, parameter, rowBounds, (ResultHandler)null, boundSql); if (!this.dialect.afterCount(count, parameter, rowBounds)) { Object var12 = this.dialect.afterPage(new ArrayList(), parameter, rowBounds); return var12; } } resultList = ExecutorUtil.pageQuery(this.dialect, executor, ms, parameter, rowBounds, resultHandler, boundSql, cacheKey); } else { resultList = executor.query(ms, parameter, rowBounds, resultHandler, cacheKey, boundSql); } Object var16 = this.dialect.afterPage(resultList, parameter, rowBounds); return var16; } }
this.dialect.skip方法判断是否跳过分页,其实也就是查看是否具备分页的条件。
3、PageHelper
public boolean skip(MappedStatement ms, Object parameterObject, RowBounds rowBounds) { if (ms.getId().endsWith("_COUNT")) { throw new RuntimeException("在系统中发现了多个分页插件,请检查系统配置!"); } else { Page page = this.pageParams.getPage(parameterObject, rowBounds); if (page == null) { return true; } else { if (StringUtil.isEmpty(page.getCountColumn())) { page.setCountColumn(this.pageParams.getCountColumn()); } this.autoDialect.initDelegateDialect(ms); return false; } } }
this.pageParams.getPage方法是从参数中获取分页信息。
4、PageParams 分页参数
public Page getPage(Object parameterObject, RowBounds rowBounds) { Page page = PageHelper.getLocalPage(); if (page == null) { if (rowBounds != RowBounds.DEFAULT) { if (this.offsetAsPageNum) { page = new Page(rowBounds.getOffset(), rowBounds.getLimit(), this.rowBoundsWithCount); } else { page = new Page(new int[]{rowBounds.getOffset(), rowBounds.getLimit()}, this.rowBoundsWithCount); page.setReasonable(false); } if (rowBounds instanceof PageRowBounds) { PageRowBounds pageRowBounds = (PageRowBounds)rowBounds; page.setCount(pageRowBounds.getCount() == null || pageRowBounds.getCount()); } } else if (parameterObject instanceof IPage || this.supportMethodsArguments) { try { page = PageObjectUtil.getPageFromObject(parameterObject, false); } catch (Exception var5) { return null; } } if (page == null) { return null; } PageHelper.setLocalPage(page); } return page; }
如果this.supportMethodsArguments为true,也就是在application.properties/application.yml中配置了pagehelper.support-methods-arguments=true,就会执行PageObjectUtil.getPageFromObject方法,从参数中提取分页信息。
5、PageObjectUtil
public staticPage getPageFromObject(Object params, boolean required) { if (params == null) { throw new PageException("无法获取分页查询参数!"); } else if (params instanceof IPage) { IPage pageParams = (IPage)params; Page page = null; if (pageParams.getPageNum() != null && pageParams.getPageSize() != null) { page = new Page(pageParams.getPageNum(), pageParams.getPageSize()); } if (StringUtil.isNotEmpty(pageParams.getOrderBy())) { if (page != null) { page.setOrderBy(pageParams.getOrderBy()); } else { page = new Page(); page.setOrderBy(pageParams.getOrderBy()); page.setOrderByonly(true); } } return page; } else { metaObject paramsObject = null; if (hasRequest && requestClass.isAssignableFrom(params.getClass())) { try { paramsObject = metaObjectUtil.forObject(getParameterMap.invoke(params)); } catch (Exception var11) { } } else { paramsObject = metaObjectUtil.forObject(params); } if (paramsObject == null) { throw new PageException("分页查询参数处理失败!"); } else { Object orderBy = getParamValue(paramsObject, "orderBy", false); boolean hasOrderBy = false; if (orderBy != null && orderBy.toString().length() > 0) { hasOrderBy = true; } int pageNum; int pageSize; Object _count; try { Object _pageNum = getParamValue(paramsObject, "pageNum", required); _count = getParamValue(paramsObject, "pageSize", required); if (_pageNum == null || _count == null) { if (hasOrderBy) { Page page = new Page(); page.setOrderBy(orderBy.toString()); page.setOrderByonly(true); return page; } return null; } pageNum = Integer.parseInt(String.valueOf(_pageNum)); pageSize = Integer.parseInt(String.valueOf(_count)); } catch (NumberFormatException var12) { throw new PageException("分页参数不是合法的数字类型!", var12); } Page page = new Page(pageNum, pageSize); _count = getParamValue(paramsObject, "count", false); if (_count != null) { page.setCount(Boolean.valueOf(String.valueOf(_count))); } if (hasOrderBy) { page.setOrderBy(orderBy.toString()); } Object reasonable = getParamValue(paramsObject, "reasonable", false); if (reasonable != null) { page.setReasonable(Boolean.valueOf(String.valueOf(reasonable))); } Object pageSizeZero = getParamValue(paramsObject, "pageSizeZero", false); if (pageSizeZero != null) { page.setPageSizeZero(Boolean.valueOf(String.valueOf(pageSizeZero))); } return page; } } }
可以看到,如果是自定义的参数对象,会将对象的属性都解析出来。如果同时存在pageNum和pageSize属性,并且能转化为数字类型,则创建并向上级返回Page对象,然后在拦截器中调用ExecutorUtil.pageQuery方法进行分页查询。
至此,就能明白为什么会触发PageHelper的隐式分页了。
PS:如果在使用MyBatis时,未对参数进行对象的封装,采用直接传多个参数的方式,如下形式:
ListgetStudents(@Param("pageNum")Integer num, @Param("pageSize")Integer size, @Param("age")Integer age);
也是可以触发隐式分页的。这是由于@Param指定的参数名为pageNum和pageSize,导致这两个参数会被提取。如果改成@Param("pageNo")和@Param("pageSize"),便不会触发。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)