pagehelper.startpage原理
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
pagehelper.startpage原理
PageHelper是一款开源的MyBatis分页插件,可以为我们MyBatis的分页功能提供方便快捷的支持。而其中,startPage无疑是PageHelper详细中的重要方法之一。本文将针对pageHelper.startPage方法进行详细介绍,给出它的工作原理及实现细节。
一、实现原理
从最初看到pagehelper.startPage方法的形式可以看出,它是在Mapper类中提供的,我们通过调用它指定所需要的分页信息,包括当前页数,每页数据数量等,然后再通过SQL查询得到所需要的分页数据,最终将分页数据返回给用户。其中startPage方法被称为分页控制器,在MyBatis中,它将通过ThreadLocal方式储存用户指定的分页数据,并根据这些数据在查询方法执行时对SQL语句进行改写,以达到分页的目的。
在PageHelper中,startPage主要执行了以下几个工作
1.为当前线程储存用户指定的分页参数:Page (currentPage,pageSize);
2.使用Page构造一个Page对象,用于封装从数据库中查询出来的数据
3.计算出需要进行的SQL改写,例如:将“SELECT * FROM table”改写成“SELECT * FROM table WHERE rownum >= ? AND rownum <= ?”
其中第一点相对比较简单,第二点和第三点的实现稍稍复杂。
二、PageHelper源码分析
1. ThreadLocal的储存
PageHelper使用ThreadLocal方式储存用户指定的分页参数,这种方式下,用户的分页参数只能在当前线程中使用,这样做的好处在于每个线程都可以使用自己的分页参数,防止参数混乱。具体实现如下:
``` public static void startPage(int pageNum, int pageSize, boolean count){ //为当前线程的Page 对象赋值 Page page = new
Page(pageNum,pageSize,count);
LOCAL_PAGE.set(page); } ```
通过这样的代码,我们可以看到page对象是以ThreadLocal的形式存储在LOCAL_PAGE变量中,即在当前线程中存储了一个Page对象。在MyBatis查询过程中,Page对象将在筛选器(Interceptor)中被读取到,并从中获得用户指定的分页信息。
2. MyBatis筛选器的改写
MyBatis的筛选器是MyBatis插件中的核心部分,它
可以拦截MyBatis的执行过程并修改其执行逻辑,被PageHelper用来改写MyBatis查询逻辑。
PageHelper的筛选器类是PageInterceptor,它主要
通过实现Interceptor接口来拦截MyBatis执行过程,并
将用户指定的分页参数转化为SQL查询条件。具体代码实
现如下:
``` public Object intercept(Invocation invocation) throws Throwable { boolean isSupportedStatement =
PluginUtils.isSupportedStatement(invocation.getTarg
et()); Object parameter =
invocation.getArgs()[1];//查询参数 RowBounds rowBounds = ((MappedStatement)
invocation.getArgs()[0]).getRowBounds(); Page page = LocalPageParameter.get();//获取当前线程
的Page对象 if (isSupportedStatement && rowBounds == DEFAULT_ROWBOUNDS && page != null &&
page.isUseFlag()) { //根据Page对象计算出分页
查询条件并应用到sql语句中 String originalSql = (String) invocation.getArgs()[0]; //
START_PAGE也是PageHelper提供的常量,专门用于计算分
页参数 String newSql =
PageSqlUtil.generatePageSql(originalSql, page, DIALECT); invocation.getArgs()[0] = buildNewMappedStatement(invocation, newSql, parameter); } return invocation.proceed(); }
```
interceptor方法中最重要的一点就是生成分页查询条件,这部分代码被写在了PageSqlUtil.generatePageSql 方法中。在每次分页查询时,MyBatis会在执行查询前首先调用PageInterceptor的interceptor方法,判断当前查询是否需要分页,并将当前线程的分页参数传给PageSqlUtil.generatePageSql()方法进行分页条件生成。
generatePageSql方法中使用了StartPageHelper和EndPageHelper两个内部类来计算当前分页条件。StartPageHelper类实现了如下功能:
``` public static String
generateQuerySql(String sql){ return "SELECT * FROM (SELECT INNER_TABLE.*,ROWNUM AS RN FROM (" + sql+ ") INNER_TABLE WHERE ROWNUM <= ?) WHERE RN > ?"; } ```
这段代码的作用是将原始SELECT语句包裹成一个子查询,同时新增一个列表示当前行编号,通过这种方式获取