pagehelper.startpage原理

合集下载
相关主题
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 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语句包裹成一个子查询,同时新增一个列表示当前行编号,通过这种方式获取

相关文档
最新文档