1,场景
错误:
//因为查询前要先去数据库查询几个条件,就会查询数据库。导致分页参数被(1)号查询消费了,所以(2)查询就没有使用到分页参数 public PageInfo<ArticleInfo> findPage(ArticleInfo entity) { PageHelper.startPage(entity.getPageNum(), entity.getPageSize()); if (entity.getTopicId() != null) { List<String> codes = new ArrayList<>(); (1)BaikeTopic baikeTopic = itBaikeService.get(entity.getTopicId()); codes.add(baikeTopic.getTopicCode()); List<String> allCodesById = itBaikeService.getAllCodesById(entity.getTopicId(), codes); entity.setTopicCode(StringUtils.join(allCodesById, ",")); } (2)List<ArticleInfo> list = this.findList(entity); list.forEach((e) -> { e.setStatusName(ArticleEnum.find(e.getStatus()).getName()); e.setApproveBy(itBaikeService.getCheckUserInfo(e.getTopicCode())); }); return new PageInfo<>(list); }
正确 :
PageHelper.startPage(entity.getPageNum(), entity.getPageSize());应该放在(2)查询上面
2,原因分析
PageHelper 方法使用了静态的 ThreadLocal 参数,分页参数和线程是绑定的。只要你可以保证在 PageHelper 方法调用后紧跟 MyBatis 查询方法,这就是安全的。因为 PageHelper 在 finally 代码段中自动清除了 ThreadLocal 存储的对象。
3,PageHelper源码分析
@Intercepts({@Signature(
type = Executor.class,
method = "query",
args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}
), @Signature(
type = Executor.class,
method = "query",
args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}
)})
public class PageInterceptor implements Interceptor {
protected Cache<CacheKey, MappedStatement> msCountMap = null;
private Dialect dialect;
private String default_dialect_class = "com.github.pagehelper.PageHelper";
private Field additionalParametersField;public PageInterceptor() {
}public Object intercept(Invocation invocation) throws Throwable {
try{
//处理SQLString pageSql = this.dialect.getPageSql(ms, boundSql, parameter, rowBounds, cacheKey);
}finally { //清楚ThreadLocal中存储的分页参数 this.dialect.afterAll();
public void remove() { ThreadLocalMap m = getMap(Thread.currentThread()); if (m != null) m.remove(this); }
}
}
}
public String getPageSql(MappedStatement ms, BoundSql boundSql, Object parameterObject, RowBounds rowBounds, CacheKey pageKey) { String sql = boundSql.getSql(); //获取分页数据 Page page = this.getLocalPage(); //重置查询sql return this.getPageSql(sql, page, pageKey); }
public String getPageSql(String sql, Page page, CacheKey pageKey) { StringBuilder sqlBuilder = new StringBuilder(sql.length() + 14); sqlBuilder.append(sql); if (page.getStartRow() == 0) { sqlBuilder.append(" LIMIT "); sqlBuilder.append(page.getPageSize()); } else { sqlBuilder.append(" LIMIT "); sqlBuilder.append(page.getStartRow()); sqlBuilder.append(","); sqlBuilder.append(page.getPageSize()); pageKey.update(page.getStartRow()); } pageKey.update(page.getPageSize()); return sqlBuilder.toString(); }
PageHelper.startPage(entity.getPageNum(), entity.getPageSize());
PageHelper继承了PageMethod
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // package com.github.pagehelper.page; import com.github.pagehelper.ISelect; import com.github.pagehelper.Page; import com.github.pagehelper.util.PageObjectUtil; public abstract class PageMethod { protected static final ThreadLocal<Page> LOCAL_PAGE = new ThreadLocal(); public PageMethod() { } protected static void setLocalPage(Page page) { LOCAL_PAGE.set(page); } public static <T> Page<T> getLocalPage() { return (Page)LOCAL_PAGE.get(); } public static void clearPage() { LOCAL_PAGE.remove(); } public static long count(ISelect select) { Page<?> page = startPage(1, -1, true); select.doSelect(); return page.getTotal(); } public static <E> Page<E> startPage(int pageNum, int pageSize) { return startPage(pageNum, pageSize, true); } public static <E> Page<E> startPage(int pageNum, int pageSize, boolean count) { Page<E> page = new Page(pageNum, pageSize, count); setLocalPage(page); return page; } public static <E> Page<E> offsetPage(int offset, int limit) { return offsetPage(offset, limit, true); } public static <E> Page<E> offsetPage(int offset, int limit, boolean count) { Page<E> page = new Page(new int[]{offset, limit}, count); setLocalPage(page); return page; } public static <E> Page<E> startPage(Object params) { Page<E> page = PageObjectUtil.getPageFromObject(params, true); setLocalPage(page); return page; } }
4,mybatis插件原理