PageHelper分页
<!-- pagehelper 分页插件 --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> </dependency>
pagehelper:
helperDialect: mysql
supportMethodsArguments: false
params: count=countSql
PageHelper.startPage(1, 10);
// Configuration.java private void parseConfiguration(XNode root) { try { ... this.pluginElement(root.evalNode("plugins")); ... } catch (Exception var3) { throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + var3, var3); } } private void pluginElement(XNode parent) throws Exception { if (parent != null) { Iterator var2 = parent.getChildren().iterator(); while(var2.hasNext()) { XNode child = (XNode)var2.next(); String interceptor = child.getStringAttribute("interceptor"); Properties properties = child.getChildrenAsProperties(); Interceptor interceptorInstance = (Interceptor)this.resolveClass(interceptor).getDeclaredConstructor().newInstance(); interceptorInstance.setProperties(properties); this.configuration.addInterceptor(interceptorInstance); } } }
// Configuration.java public void addInterceptor(Interceptor interceptor) { this.interceptorChain.addInterceptor(interceptor); } // InterceptorChain.java private final List<Interceptor> interceptors = new ArrayList(); public void addInterceptor(Interceptor interceptor) { this.interceptors.add(interceptor); }
2、
public Executor newExecutor(Transaction transaction, ExecutorType executorType) { executorType = executorType == null ? this.defaultExecutorType : executorType; executorType = executorType == null ? ExecutorType.SIMPLE : executorType; Object executor; if (ExecutorType.BATCH == executorType) { executor = new BatchExecutor(this, transaction); } else if (ExecutorType.REUSE == executorType) { executor = new ReuseExecutor(this, transaction); } else { executor = new SimpleExecutor(this, transaction); } if (this.cacheEnabled) { executor = new CachingExecutor((Executor)executor); } Executor executor = (Executor)this.interceptorChain.pluginAll(executor); return executor; }
// InterceptorChain.java public Object pluginAll(Object target) { Interceptor interceptor; for(Iterator var2 = this.interceptors.iterator(); var2.hasNext(); target = interceptor.plugin(target)) { interceptor = (Interceptor)var2.next(); } return target; }
// Interceptor.java default Object plugin(Object target) { return Plugin.wrap(target, this); } // Plugin.java public static Object wrap(Object target, Interceptor interceptor) { Map<Class<?>, Set<Method>> signatureMap = getSignatureMap(interceptor); Class<?> type = target.getClass(); Class<?>[] interfaces = getAllInterfaces(type, signatureMap); return interfaces.length > 0 ? Proxy.newProxyInstance(type.getClassLoader(), interfaces, new Plugin(target, interceptor, signatureMap)) : target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { Set<Method> methods = (Set)this.signatureMap.get(method.getDeclaringClass()); return methods != null && methods.contains(method) ? this.interceptor.intercept(new Invocation(this.target, method, args)) : method.invoke(this.target, args); } catch (Exception var5) { throw ExceptionUtil.unwrapThrowable(var5); } }
// Plugin.java private static Map<Class<?>, Set<Method>> getSignatureMap(Interceptor interceptor) { Intercepts interceptsAnnotation = (Intercepts)interceptor.getClass().getAnnotation(Intercepts.class); if (interceptsAnnotation == null) { throw new PluginException("No @Intercepts annotation was found in interceptor " + interceptor.getClass().getName()); } else { Signature[] sigs = interceptsAnnotation.value(); Map<Class<?>, Set<Method>> signatureMap = new HashMap(); Signature[] var4 = sigs; int var5 = sigs.length; for(int var6 = 0; var6 < var5; ++var6) { Signature sig = var4[var6]; Set<Method> methods = (Set)MapUtil.computeIfAbsent(signatureMap, sig.type(), (k) -> { return new HashSet(); }); try { Method method = sig.type().getMethod(sig.method(), sig.args()); methods.add(method); } catch (NoSuchMethodException var10) { throw new PluginException("Could not find method on " + sig.type() + " named " + sig.method() + ". Cause: " + var10, var10); } } return signatureMap; } }
// PageInterceptor.java @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} )})
// Executor.java <E> List<E> query(MappedStatement var1, Object var2, RowBounds var3, ResultHandler var4, CacheKey var5, BoundSql var6) throws SQLException; <E> List<E> query(MappedStatement var1, Object var2, RowBounds var3, ResultHandler var4) throws SQLException;
// PageHelperAutoConfiguration.java public void afterPropertiesSet() throws Exception { PageInterceptor interceptor = new PageInterceptor(); interceptor.setProperties(this.properties); // 后面有 Iterator var2 = this.sqlSessionFactoryList.iterator(); while(var2.hasNext()) { SqlSessionFactory sqlSessionFactory = (SqlSessionFactory)var2.next(); org.apache.ibatis.session.Configuration configuration = sqlSessionFactory.getConfiguration(); if (!this.containsInterceptor(configuration, interceptor)) { configuration.addInterceptor(interceptor); } } }
// PageHelper.java public class PageHelper extends PageMethod implements Dialect, BoundSqlInterceptor.Chain
// PageMethod.java 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 = getLocalPage(); if (oldPage != null && oldPage.isOrderByOnly()) { page.setOrderBy(oldPage.getOrderBy()); } setLocalPage(page); return page; } protected static final ThreadLocal<Page> LOCAL_PAGE = new ThreadLocal(); protected static void setLocalPage(Page page) { LOCAL_PAGE.set(page); }
private Page(int pageNum, int pageSize, boolean count, Boolean reasonable) { super(0); this.stackTrace = PageInterceptor.isDebug() ? StackTraceUtil.current() : null; this.count = true; if (pageNum == 1 && pageSize == Integer.MAX_VALUE) { this.pageSizeZero = true; pageSize = 0; } this.pageNum = pageNum; this.pageSize = pageSize; this.count = count; this.calculateStartAndEndRow(); this.setReasonable(reasonable); } private void calculateStartAndEndRow() { this.startRow = this.pageNum > 0 ? (long)((this.pageNum - 1) * this.pageSize) : 0L; this.endRow = this.startRow + (long)(this.pageSize * (this.pageNum > 0 ? 1 : 0)); }
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 BoundSqlInterceptor.Chain) { boundSql = ((BoundSqlInterceptor.Chain)this.dialect).doBoundSql(Type.ORIGINAL, boundSql, cacheKey); } List resultList; if (!this.dialect.skip(ms, parameter, rowBounds)) { this.debugStackTraceLog(); 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; } finally { if (this.dialect != null) { this.dialect.afterAll(); } } }
public static <E> List<E> pageQuery(Dialect dialect, Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql, CacheKey cacheKey) throws SQLException { if (!dialect.beforePage(ms, parameter, rowBounds)) { return executor.query(ms, parameter, RowBounds.DEFAULT, resultHandler, cacheKey, boundSql); } else { parameter = dialect.processParameterObject(ms, parameter, boundSql, cacheKey); String pageSql = dialect.getPageSql(ms, boundSql, parameter, rowBounds, cacheKey); BoundSql pageBoundSql = new BoundSql(ms.getConfiguration(), pageSql, boundSql.getParameterMappings(), parameter); Map<String, Object> additionalParameters = getAdditionalParameter(boundSql); Iterator var12 = additionalParameters.keySet().iterator(); while(var12.hasNext()) { String key = (String)var12.next(); pageBoundSql.setAdditionalParameter(key, additionalParameters.get(key)); } if (dialect instanceof BoundSqlInterceptor.Chain) { pageBoundSql = ((BoundSqlInterceptor.Chain)dialect).doBoundSql(Type.PAGE_SQL, pageBoundSql, cacheKey); } return executor.query(ms, parameter, RowBounds.DEFAULT, resultHandler, cacheKey, pageBoundSql); } }
// PageInterceptor.java this.default_dialect_class = "com.github.pagehelper.PageHelper"; public void setProperties(Properties properties) { ... String dialectClass = properties.getProperty("dialect"); if (StringUtil.isEmpty(dialectClass)) { dialectClass = this.default_dialect_class; } try { Class<?> aClass = Class.forName(dialectClass); this.dialect = (Dialect)aClass.newInstance(); } catch (Exception var7) { throw new PageException(var7); } this.dialect.setProperties(properties); } // PageHelper.java public void setProperties(Properties properties) { ... this.autoDialect = new PageAutoDialect(); ... this.autoDialect.setProperties(properties); ... } // PageAutoDialect.java public void setProperties(Properties properties) { ... String dialect = properties.getProperty("helperDialect"); String runtimeDialect = properties.getProperty("autoRuntimeDialect"); if (StringUtil.isNotEmpty(runtimeDialect) && "TRUE".equalsIgnoreCase(runtimeDialect)) { this.autoDialect = false; this.properties = properties; } else if (StringUtil.isEmpty(dialect)) { this.autoDialect = true; this.properties = properties; } else { this.autoDialect = false; this.delegate = instanceDialect(dialect, properties); } } public static AbstractHelperDialect instanceDialect(String dialectClass, Properties properties) { if (StringUtil.isEmpty(dialectClass)) { throw new PageException("使用 PageHelper 分页插件时,必须设置 helper 属性"); } else { AbstractHelperDialect dialect; try { Class sqlDialectClass = resloveDialectClass(dialectClass); if (!AbstractHelperDialect.class.isAssignableFrom(sqlDialectClass)) { throw new PageException("使用 PageHelper 时,方言必须是实现 " + AbstractHelperDialect.class.getCanonicalName() + " 接口的实现类!"); } dialect = (AbstractHelperDialect)sqlDialectClass.newInstance(); } catch (Exception var4) { throw new PageException("初始化 helper [" + dialectClass + "]时出错:" + var4.getMessage(), var4); } dialect.setProperties(properties); return dialect; } } public static Class resloveDialectClass(String className) throws Exception { return dialectAliasMap.containsKey(className.toLowerCase()) ? (Class)dialectAliasMap.get(className.toLowerCase()) : Class.forName(className); }
// PageAutoDialect.java static { ... registerDialectAlias("mysql", MySqlDialect.class); ... } public static void registerDialectAlias(String alias, Class<? extends Dialect> dialectClass) { dialectAliasMap.put(alias, dialectClass); }
// PageHelper.java public Object processParameterObject(MappedStatement ms, Object parameterObject, BoundSql boundSql, CacheKey pageKey) { return this.autoDialect.getDelegate().processParameterObject(ms, parameterObject, boundSql, pageKey); }
// AbstractHelperDialect.java public Object processParameterObject(MappedStatement ms, Object parameterObject, BoundSql boundSql, CacheKey pageKey) { Page page = this.getLocalPage(); if (page.isOrderByOnly()) { return parameterObject; } else { Map<String, Object> paramMap = null; if (parameterObject == null) { paramMap = new HashMap(); } else if (parameterObject instanceof Map) { paramMap = new HashMap(); paramMap.putAll((Map)parameterObject); } else { paramMap = new HashMap(); if (ms.getSqlSource() instanceof ProviderSqlSource) { String[] providerMethodArgumentNames = ExecutorUtil.getProviderMethodArgumentNames((ProviderSqlSource)ms.getSqlSource()); if (providerMethodArgumentNames != null && providerMethodArgumentNames.length == 1) { paramMap.put(providerMethodArgumentNames[0], parameterObject); paramMap.put("param1", parameterObject); } } boolean hasTypeHandler = ms.getConfiguration().getTypeHandlerRegistry().hasTypeHandler(parameterObject.getClass()); MetaObject metaObject = MetaObjectUtil.forObject(parameterObject); if (!hasTypeHandler) { String[] var9 = metaObject.getGetterNames(); int var10 = var9.length; for(int var11 = 0; var11 < var10; ++var11) { String name = var9[var11]; paramMap.put(name, metaObject.getValue(name)); } } if (boundSql.getParameterMappings() != null && boundSql.getParameterMappings().size() > 0) { Iterator var14 = boundSql.getParameterMappings().iterator(); ParameterMapping parameterMapping; String name; do { do { do { do { if (!var14.hasNext()) { return this.processPageParameter(ms, paramMap, page, boundSql, pageKey); } parameterMapping = (ParameterMapping)var14.next(); name = parameterMapping.getProperty(); } while(name.equals("First_PageHelper")); } while(name.equals("Second_PageHelper")); } while(paramMap.get(name) != null); } while(!hasTypeHandler && !parameterMapping.getJavaType().equals(parameterObject.getClass())); paramMap.put(name, parameterObject); } } return this.processPageParameter(ms, paramMap, page, boundSql, pageKey); } } // MySqlDialect.java public Object processPageParameter(MappedStatement ms, Map<String, Object> paramMap, Page page, BoundSql boundSql, CacheKey pageKey) { paramMap.put("First_PageHelper", page.getStartRow()); paramMap.put("Second_PageHelper", page.getPageSize()); pageKey.update(page.getStartRow()); pageKey.update(page.getPageSize()); if (boundSql.getParameterMappings() != null) { List<ParameterMapping> newParameterMappings = new ArrayList(boundSql.getParameterMappings()); if (page.getStartRow() == 0L) { newParameterMappings.add((new ParameterMapping.Builder(ms.getConfiguration(), "Second_PageHelper", Integer.TYPE)).build()); } else { newParameterMappings.add((new ParameterMapping.Builder(ms.getConfiguration(), "First_PageHelper", Long.TYPE)).build()); newParameterMappings.add((new ParameterMapping.Builder(ms.getConfiguration(), "Second_PageHelper", Integer.TYPE)).build()); } MetaObject metaObject = MetaObjectUtil.forObject(boundSql); metaObject.setValue("parameterMappings", newParameterMappings); } return paramMap; }
// AbstractHelperDialect.java public String getPageSql(MappedStatement ms, BoundSql boundSql, Object parameterObject, RowBounds rowBounds, CacheKey pageKey) { String sql = boundSql.getSql(); Page page = this.getLocalPage(); String orderBy = page.getOrderBy(); if (StringUtil.isNotEmpty(orderBy)) { pageKey.update(orderBy); sql = OrderByParser.converToOrderBySql(sql, orderBy, this.jSqlParser); } return page.isOrderByOnly() ? sql : this.getPageSql(sql, page, pageKey); } // MySqlDialect.java public String getPageSql(String sql, Page page, CacheKey pageKey) { StringBuilder sqlBuilder = new StringBuilder(sql.length() + 14); sqlBuilder.append(sql); if (page.getStartRow() == 0L) { sqlBuilder.append("\n LIMIT ? "); } else { sqlBuilder.append("\n LIMIT ?, ? "); } return sqlBuilder.toString(); }
// PageInterceptor.java public Object intercept(Invocation invocation) throws Throwable { try { ... } finally { if (this.dialect != null) { this.dialect.afterAll(); } } } // PageHelper.java public void afterAll() { AbstractHelperDialect delegate = this.autoDialect.getDelegate(); if (delegate != null) { delegate.afterAll(); this.autoDialect.clearDelegate(); } clearPage(); } // PageMethod.java public static void clearPage() { LOCAL_PAGE.remove(); }
// PageInterceptor.java public Object intercept(Invocation invocation) throws Throwable { try { ... if (!this.dialect.skip(ms, parameter, rowBounds)) { ... } else { resultList = executor.query(ms, parameter, rowBounds, resultHandler, cacheKey, boundSql); } ... } finally { ... } } // PageHelper.java public boolean skip(MappedStatement ms, Object parameterObject, RowBounds rowBounds) { 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, page.getDialectClass()); return false; } } // PageParams.java public Page getPage(Object parameterObject, RowBounds rowBounds) { Page page = PageHelper.getLocalPage(); if (page == null) { if (rowBounds != RowBounds.DEFAULT) { . ... } else if (parameterObject instanceof IPage || this.supportMethodsArguments) { ... } if (page == null) { return null; } PageHelper.setLocalPage(page); } ... return page; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理