mybatis 分頁插件 pagehelper

pagehelper項(xiàng)目github地址

在使用Mybatis時(shí),大量的查詢要寫分頁,寫分頁需要先寫一個(gè)查詢count語句,然后再寫一個(gè)真正分頁查詢的語句,代碼不僅僅大量重復(fù)而且完全沒有必要。于是希望只寫一個(gè)select語句,count由插件根據(jù)select語句自動(dòng)完成。
mybatis 有個(gè)分頁插件 pagehelper,它本質(zhì)上是對(duì) mybatis 執(zhí)行流程進(jìn)行了增強(qiáng),添加了 limit 以及 count 查詢,屬于物理分頁。

使用起來也很簡單,分為三步:引包、配置、使用

  • 引包
    <dependency>
        <groupId>com.github.pagehelper</groupId>
        <artifactId>pagehelper</artifactId>
        <version>5.1.4</version>
    </dependency>
  • 配置

配置分頁攔截器,PageHelper的原理是基于攔截器實(shí)現(xiàn)的。
方式一:在sqlSessionFactory的bean里配置一個(gè)property
方式二:直接配置一個(gè)plugins

方式一:

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
  <property name="dataSource" ref="dataSource"/>
  
  <property name="mapperLocations">
    <array>
      <value>classpath*:com/parking/dao/*.xml</value>
    </array>
  </property>
  <property name="typeAliasesPackage" value="com.test.domain.*"/>
  
  <property name="plugins">
    <array>
      <bean class="com.github.pagehelper.PageInterceptor">
        <property name="properties">
          <value>
            helperDialect=mysql
          </value>
        </property>
      </bean>
    </array>
  </property>
</bean>

方式二:

<plugins>
    <!-- com.github.pagehelper為PageHelper類所在包名 -->
    <plugin interceptor="com.github.pagehelper.PageInterceptor">
        <property name="helperDialect" value="mysql"/>
        <!-- 該參數(shù)默認(rèn)為false -->
        <!-- 設(shè)置為true時(shí),會(huì)將RowBounds第一個(gè)參數(shù)offset當(dāng)成pageNum頁碼使用 -->
        <!-- 和startPage中的pageNum效果一樣-->
        <property name="offsetAsPageNum" value="true"/>
        <!-- 該參數(shù)默認(rèn)為false -->
        <!-- 設(shè)置為true時(shí),使用RowBounds分頁會(huì)進(jìn)行count查詢 -->
        <property name="rowBoundsWithCount" value="true"/>
        
        <!-- 設(shè)置為true時(shí),如果pageSize=0或者RowBounds.limit = 0就會(huì)查詢出全部的結(jié)果 -->
        <!-- (相當(dāng)于沒有執(zhí)行分頁查詢,但是返回結(jié)果仍然是Page類型)
        <property name="pageSizeZero" value="true"/>-->
        
        <!-- 分頁參數(shù)合理化,默認(rèn)false禁用 -->
        <!-- 啟用合理化時(shí),如果pageNum<1會(huì)查詢第一頁,如果pageNum>pages會(huì)查詢最后一頁 -->
        <!-- 禁用合理化時(shí),如果pageNum<1或pageNum>pages會(huì)返回空數(shù)據(jù) -->
        <property name="reasonable" value="true"/>
        <!-- 為了支持startPage(Object params)方法 -->
        <!-- 增加了一個(gè)`params`參數(shù)來配置參數(shù)映射,用于從Map或ServletRequest中取值 -->
        <!-- 可以配置pageNum,pageSize,count,pageSizeZero,reasonable,不配置映射的用默認(rèn)值 -->
        <!-- 不理解該含義的前提下,不要隨便復(fù)制該配置 
        <property name="params" value="pageNum=start;pageSize=limit;"/>    -->
    </plugin>
  </plugins>
  <!-- 注意 plugins 在mybatis-config.xml文件中的位置,符合mybatis-3-config.dtd 中指定的順序 -->
  <!ELEMENT configuration (properties?, settings?, typeAliases?, typeHandlers?, 
    objectFactory?, objectWrapperFactory?, plugins?, environments?, databaseIdProvider?, mappers?)>
  • 使用

PageHelper.startPage 靜態(tài)方法調(diào)用:

//獲取第1頁,10條內(nèi)容,默認(rèn)查詢總數(shù)count
PageHelper.startPage(1, 10);
List<Country> list = countryMapper.selectAll();
//用PageInfo對(duì)結(jié)果進(jìn)行包裝
PageInfo page = new PageInfo(list);
//測試PageInfo全部屬性
//PageInfo包含了非常全面的分頁屬性
assertEquals(1, page.getPageNum());
assertEquals(10, page.getPageSize());
assertEquals(1, page.getStartRow());
assertEquals(10, page.getEndRow());
assertEquals(183, page.getTotal());
assertEquals(19, page.getPages());
assertEquals(1, page.getFirstPage());
assertEquals(8, page.getLastPage());
assertEquals(true, page.isFirstPage());
assertEquals(false, page.isLastPage());
assertEquals(false, page.isHasPreviousPage());
assertEquals(true, page.isHasNextPage());
pagehelper.PNG

更多詳細(xì)的參數(shù)配置及使用方法,請(qǐng)參考官方文檔。

這樣實(shí)現(xiàn)分頁安全嗎?下面摘自項(xiàng)目原文:

什么時(shí)候會(huì)導(dǎo)致不安全的分頁?

PageHelper 方法使用了靜態(tài)的 ThreadLocal 參數(shù),分頁參數(shù)和線程是綁定的。

只要你可以保證在 PageHelper 方法調(diào)用后緊跟 MyBatis 查詢方法,這就是安全的。因?yàn)?PageHelper 在 finally 代碼段中自動(dòng)清除了 ThreadLocal 存儲(chǔ)的對(duì)象。

如果代碼在進(jìn)入 Executor 前發(fā)生異常,就會(huì)導(dǎo)致線程不可用,這屬于人為的 Bug(例如接口方法和 XML 中的不匹配,導(dǎo)致找不到 MappedStatement 時(shí)), 這種情況由于線程不可用,也不會(huì)導(dǎo)致 ThreadLocal 參數(shù)被錯(cuò)誤的使用。

但是如果你寫出下面這樣的代碼,就是不安全的用法:

PageHelper.startPage(1, 10);
List<Country> list;
if(param1 != null){
    list = countryMapper.selectIf(param1);
} else {
    list = new ArrayList<Country>();
}
這種情況下由于 param1 存在 null 的情況,就會(huì)導(dǎo)致 PageHelper 生產(chǎn)了一個(gè)分頁參數(shù),但是沒有被消費(fèi),這個(gè)參數(shù)就會(huì)一直保留在這個(gè)線程上。當(dāng)這個(gè)線程再次被使用時(shí),就可能導(dǎo)致不該分頁的方法去消費(fèi)這個(gè)分頁參數(shù),這就產(chǎn)生了莫名其妙的分頁。

上面這個(gè)代碼,應(yīng)該寫成下面這個(gè)樣子:

List<Country> list;
if(param1 != null){
    PageHelper.startPage(1, 10);
    list = countryMapper.selectIf(param1);
} else {
    list = new ArrayList<Country>();
}
這種寫法就能保證安全。

如果你對(duì)此不放心,你可以手動(dòng)清理 ThreadLocal 存儲(chǔ)的分頁參數(shù),可以像下面這樣使用:

List<Country> list;
if(param1 != null){
    PageHelper.startPage(1, 10);
    try{
        list = countryMapper.selectAll();
    } finally {
        PageHelper.clearPage();
    }
} else {
    list = new ArrayList<Country>();
}
這么寫很不好看,而且沒有必要。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 在實(shí)際的項(xiàng)目開發(fā)中,常常需要使用到分頁,分頁方式分為兩種:前端分頁和后端分頁。 前端分頁一次ajax請(qǐng)求數(shù)據(jù)的所有...
    意識(shí)流丶閱讀 70,645評(píng)論 2 70
  • 分頁是項(xiàng)目中經(jīng)常會(huì)使用到的功能,我們可以自己手動(dòng)在sql語句中進(jìn)行分頁,但是這樣比較麻煩,Mybatis的Page...
    就沒一個(gè)昵稱能用閱讀 11,958評(píng)論 0 3
  • 在web開發(fā)過程中涉及到表格時(shí),例如dataTable,就會(huì)產(chǎn)生分頁的需求,通常我們將分頁方式分為兩種:前端分頁和...
    創(chuàng)新科技寶典閱讀 2,119評(píng)論 0 0
  • 以前在網(wǎng)上看到過一張圖片,上身理想下身現(xiàn)實(shí)。之前懵懵懂懂的理解過,但是現(xiàn)在可能比之前更懂。 于是,我現(xiàn)在正...
    不要熬夜閱讀 334評(píng)論 0 0
  • 那夜好多爸爸開了家長會(huì)回來,與我說了好多。談到好幾位家長不斷提到了一個(gè)詞——“自律”。 每個(gè)班里總有幾個(gè)別人家的孩...
    我家的這些那些事兒閱讀 391評(píng)論 0 4

友情鏈接更多精彩內(nèi)容