Spring Boot 整合 PageHelper

在 PageHelper官網,對PageHelper進行了如下描述

 

如何在Spring Boot項目當中引入PageHelper進行分頁處理呢?

第一步:添加maven依賴

<dependency>
	<groupId>com.github.pagehelper</groupId>
	<artifactId>pagehelper-spring-boot-starter</artifactId>
	<version>1.2.3</version>
</dependency>

第二步:添加properties配置

#pagehelper分頁插件配置
pagehelper.helper-dialect=mysql
pagehelper.reasonable=true
pagehelper.support-methods-arguments=true
pagehelper.params=count=countSql

第三步:在你的查詢語句之前進行分頁處理

//第幾頁
Integer pageNum = 1;
//一頁多少數據
Integer pageSize = 10;
//開始分頁
PageHelper.startPage(pageNum,pageSize);
//查詢語句
studentService.selectAll();

通過以上三步,就已經實現了分頁處理了。

 

那麼,PageHelper是如何實現分頁處理的呢?

PageHelper分頁原理

第一步:我們首先得理解mybatis的plugin,可以在mybatis官方文檔當中,找到如下描述

那麼,我們可否實現自己的plugin,來打印需要執行的sql語句呢?

可以

比如我們先按照文檔,寫一個MyPlugin

@Intercepts({@Signature(
        type= StatementHandler.class,
        method = "prepare",
        args = {Connection.class,Integer.class})})
public class MyPlugin implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        StatementHandler statementHandler= (StatementHandler) invocation.getTarget();
        BoundSql boundSql = statementHandler.getBoundSql();
        //打印sql語句
        System.out.println("MyPlugin" + boundSql.getSql());
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target,this);
    }

    @Override
    public void setProperties(Properties properties) {
        String dialect = properties.getProperty("dialect");
        System.out.println("dialect="+dialect);
    }
}

  然後在springboot當中註冊成Bean

@Bean
public MyPlugin myPlugin(){
        MyPlugin myPlugin = new MyPlugin();
	Properties properties = new Properties();
	properties.setProperty("dialect","mysql");
	myPlugin.setProperties(properties);
	return myPlugin;
}

通過上面的兩步我們就實現了一個自己的Plugin,來打印出需要執行的sql語句

第二步:通過上面文檔的描述,我們知道,mybatis的插件就像springmvc當中的Interceptor,可以對方法進行攔截。那麼既然可以對方法進行攔截,那麼我可不可以,在每個查詢方法之前,先檢測一下當前語句是否需要分頁,假如需要分頁,我就拼接分頁的SQL語句,然後再執行拼接後的SQL語句呢?

可以,因爲PageHelper就是這樣做的

在PageHelper分頁當中,首先要執行startPage方法

//通過startPage,把當前的分頁信息保存到ThreadLocal裏面,確保每個線程之間互不影響
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());
        }
        //把信息保存到ThreadLocal裏面
        setLocalPage(page);
        return page;
    }
然後可以查看到com.github.pagehelper.PageInterceptor,一個PageHelper的Plugin。

我們在PageInterceptor.intercept這個攔截方法當中,可以找到如下兩個語句

String pageSql = this.dialect.getPageSql(ms, boundSql, parameter, rowBounds, cacheKey);
BoundSql pageBoundSql = new BoundSql(configuration, pageSql, boundSql.getParameterMappings(), parameter);

 其中,getPageSql根據每種數據庫而不同,以MySQL數據庫爲例,它的getPageSql語句如下:

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 ? ");
        } else {
            sqlBuilder.append(" LIMIT ?, ? ");
        }
        pageKey.update(page.getPageSize());
        return sqlBuilder.toString();
    }

到此,我們就知道了PageHelper如何分頁

1、通過startPage方法,把當前的分頁參數保存到ThreadLocal<Page> LOCAL_PAGE這個參數當中

2、通過com.github.pagehelper.PageInterceptor攔截要執行的query方法

3、根據dialect信息,執行不同數據庫的getPageSql方法,拼接分頁語句

4、攔截器執行getPageSql返回的新的sql語句,進行分頁查詢

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章