网站策划书格式及范文1000字免费,产品宣传短视频制作,安徽p2p网站建设,seo排名优化网站在使用springboot开发系统时#xff0c;列表查询经常会用PageHelper来进行分页。使用起来很方便#xff0c;但从未想过它的实现原理#xff0c;所以对其进行解读。
Service
public class ScUserServiceImpl extends ServiceImplScUserMapper, ScUser implements IS… 在使用springboot开发系统时列表查询经常会用PageHelper来进行分页。使用起来很方便但从未想过它的实现原理所以对其进行解读。
Service
public class ScUserServiceImpl extends ServiceImplScUserMapper, ScUser implements IScUserService {Overridepublic PageInfoScUser pageList(UserListF form) {LambdaQueryWrapperScUser qw Wrappers.ScUserlambdaQuery().like(ScUser::getName, form.getName());// 开启分页对下一条执行的sql进行分页PageScUser page PageHelper.startPage(form.getPageNum(), form.getPageSize());ListScUser userList baseMapper.selectList(qw);return new PageInfo(page);}
} 基于PageHelperv5.3.2官方文档这是一个最简单、最常用的分页demo持久层框架使用的是Mybatis-plus. 调试截图 调试过程发现3个问题点
为什么调用PageHelper.startPage()方法后可以实现分页为什么在执行sql查询前先执行select count(0) 为什么查询出来的userList不需要return直接return new PageInfo(page)就可以有数据 追踪过程 进入PageHelper.startPage()方法看到里面有一个 setLocalPage(page) 方法方法的入参page里包含了分页参数pageNum、pageSize等 setLocalPage方法对 LOCAL_PAGE 这个线程局部变量进行进行赋值 在getLocaPage方法打断点看什么时候会取出LOCAL_PAGE线程局部变量。最终发现方法落在了com.github.pagehelper.PageHelper#doBoundSql 同时在该方法的第二个入参boundSql里可以下一条要执行的sql 继续追踪看到它的上级调用方法在com.github.pagehelper.PageInterceptor#intercept PageInterceptor这个类实现了ibatis的Interceptor接口从而实现了对sql语句的拦截 intercept()这个方法的中文注释非常完整基本可以对照着阅读源码。 其中 dialect.beforeCount()这个方法会去线程局部变量LOCAL_PAGE中拿到count属性从而决定是否在分页查询前执行count(0)查询。而这个count属性在一开始我们调用PageHelper.startPage()的时候就配置了默认值true。 而 ExecutorUtil.pageQuery() 则是对查询sql进行解析配置了多种解析器兼容mysql、oracle、sqlserver、Oscar等并组装成对应的分页sql。组装好的sql将其封装为BoundSql对象再调用org.apache.ibatis.executor.Executor#query()方法执行最终拿到分页查询结果。 根据现有的结论我们可以得出分页参数是通过ThreadLocalPage的方式传递的那么第3个问题为什么分页查询结果集不需要return而是直接return page对象答案也就水落石出了。 在分页查询结束后dialect.afterPage()方法会将结果集resultList塞入到LOCAL_PAGE 这个线程局部变量里去。 问题点解答 1、为什么调用PageHelper.startPage()方法后可以实现分页 因为startPage方法将分页参数保存到了线程局部变量然后通过PageInterceptor它实现了ibatis提供的inteceptor接口对下一条即将执行的query sql进行拦截解析语义并组装为分页query sql执行并拿到结果集并存放到线程局部变量里去。 2、为什么在执行sql查询前先执行select count(0) 因为调用 PageHelper.startPage(form.getPageNum(), form.getPageSize()) 方法时传递了默认count属性值默认为true所以在分页时会执行count(0)查询总记录数。它并不影响分页的过程、结果它只是满足业务需要所做的一个查询。 如果不需要count(0)可以调用 PageHelper.startPage(form.getPageNum(), form.getPageSize(), false) 来指定。 3、为什么查询出来的userList不需要return直接return new PageInfo(page)就可以有数据 因为page是一个线程局部变量分页查询结束后PageInterceptor会调用 dialect.afterPage() 将结果集保存到page里去所以page里会有数据。 你也可以return userList但是page里的属性更加丰富它除了结果集之外还有当前页、每页记录数、总记录数等等..... 小结 经过代码追踪我明白了PageHelper的本质其实是基于ThreadLocal和ibatis提供的sql监听器实现的解开了这层神秘的面纱。这种对sql约定好的的统一处理策略非常值得学习。对也让我对mybatis的的执行过程更加好奇后续可以更进一步对mybatis的原理进行追踪和理解。