Mybatis分頁插件 -PageHelper

相關鏈接

Mybatis-Sample(分頁插件測試項目):http://git.oschina.net/free/Mybatis-Sample

 對應於oschub的項目地址:http://git.oschina.net/free/Mybatis_PageHelper

對應於github的項目地址:https://github.com/pagehelper/Mybatis-PageHelper

Mybatis項目:https://github.com/mybatis/mybatis-3

Mybatis文檔:http://mybatis.github.io/mybatis-3/zh/index.html

Mybatis專欄:Mybatis示例   Mybatis問題集

參考作者博客:http://my.oschina.net/flags/blog 

                        http://blog.csdn.net/isea533

 

Mybatis分頁插件 -PageHelper說明

如果你也在用Mybatis,建議嘗試該分頁插件,這個一定是最方便使用的分頁插件。

該插件目前支持Oracle,Mysql,MariaDB,SQLite,Hsqldb,PostgreSQL六種數據庫分頁。

版本說明

最新版本爲3.7.5

PageInfo中的judgePageBoudary方法修改:

    isLastPage = pageNum == pages && pageNum != 1;

    //改爲

    isLastPage = pageNum == pages;

 

版本3.4.1

重大bug修復,SqlParser解析sql失敗的時候返回了不帶count(*)的sql,導致查詢失敗。

產生原因,由於SqlParser在系統中出現的位置修改後,導致這裏出現錯誤。

強烈推薦各位更新到最新版本。

版本3.4.0

增加了對@SelectProvider註解方法的支持,不使用這種方式的不影響

對基本邏輯進行修改,減少反射調用和獲取BoundSql次數

對支持的數據庫全部通過完整測試

雖然變化大,但是影響範圍小,不特殊通知各位了。

使用方法

分頁插件項目中的正式代碼一共有個5Java文件,這5個文件的說明如下:

Page<E>[必須]:分頁參數類,該類繼承ArrayList,雖然分頁查詢返回的結果實際類型是Page<E>,但是可以完全不出現所有的代碼中,可以直接當成List使用。返回值不建議使用Page,建議仍然用List。如果需要用到分頁信息,使用下面的PageInfo類對List進行包裝即可。

PageHelper[必須]:分頁插件攔截器類,對Mybatis的攔截在這個類中實現。

PageInfo[可選]:Page<E>的包裝類,包含了全面的分頁屬性信息。

SqlParser[可選]:提供高效的count查詢sql。主要是智能替換原sql語句爲count(*),去除不帶參數的order by語句。需要jsqlparser-0.9.1.jar支持。

SqlUtil[必須]:分頁插件工具類,分頁插件邏輯類,分頁插件的主要實現方法都在這個類中。

引入分頁插件

引入分頁插件一共有下面3種方式,推薦使用引入分頁代碼的方式,這種方式易於控制,並且可以根據自己需求進行修改。

 

 

引入分頁代碼

將本插件中的com.github.pagehelper包(點擊進入gitosc | 點擊進入github)下面的三個類Page,PageHelperSqlUtil放到項目中,如果需要使用PageInfo(強大的分頁包裝類),也可以放到項目中。如果想使用更高效的count查詢,你也可以將SqlParser放到SqlUtil相同的包下,使用SqlParser時必須使用jsqlparser-0.9.1.jar

 

 

引入Jar包

如果你想使用本項目的jar包而不是直接引入類,你可以在這裏下載各個版本的jar包(點擊Download下的jar即可下載)

https://oss.sonatype.org/content/repositories/releases/com/github/pagehelper/pagehelper/

http://repo1.maven.org/maven2/com/github/pagehelper/pagehelper/

由於使用了sql解析工具,你還需要下載這個文件(這個文件完全獨立,不依賴其他):

SqlParser.jar:http://search.maven.org/remotecontent?filepath=com/github/jsqlparser/jsqlparser/0.9.1/jsqlparser-0.9.1.jar

SqlParser - github地址:https://github.com/JSQLParser/JSqlParser

實現通用分頁組件

 

 

 

Mybatis的plugin實現原理

 

 

 

使用PageHelper實現分頁

 

 

導入依賴

<dependency>

         <groupId>com.github.pagehelper</groupId>

         <artifactId>pagehelper</artifactId>

         <version>3.7.5</version>

      </dependency>

      <dependency>

         <groupId>com.github.jsqlparser</groupId>

         <artifactId>jsqlparser</artifactId>

         <version>0.9.1</version>

   </dependency>

 

 

配置插件

這個攔截器插件放在配置環境的上面

 

 

 

在執行查詢時設置分頁參數

  

 

  

 

可以通過Pageinfo獲取分頁的信息

Pageinfo.getpages :總頁數

 

 

在Mybatis配置xml中配置攔截器插件:

<!--

    plugins在配置文件中的位置必須符合要求,否則會報錯,順序如下:

    properties?, settings?,

    typeAliases?, typeHandlers?,

    objectFactory?,objectWrapperFactory?,

    plugins?,

    environments?, databaseIdProvider?, mappers?

-->

<plugins>

    <!-- com.github.pagehelperPageHelper類所在包名 -->

    <plugin interceptor="com.github.pagehelper.PageHelper">

        <property name="dialect" value="mysql"/>

        <!-- 該參數默認爲false -->

        <!-- 設置爲true時,會將RowBounds第一個參數offset當成pageNum頁碼使用 -->

        <!-- startPage中的pageNum效果一樣-->

        <property name="offsetAsPageNum" value="true"/>

        <!-- 該參數默認爲false -->

        <!-- 設置爲true時,使用RowBounds分頁會進行count查詢 -->

        <property name="rowBoundsWithCount" value="true"/>

        <!-- 設置爲true時,如果pageSize=0或者RowBounds.limit = 0就會查詢出全部的結果 -->

        <!-- (相當於沒有執行分頁查詢,但是返回結果仍然是Page類型)-->

        <property name="pageSizeZero" value="true"/>

        <!-- 3.3.0版本可用 - 分頁參數合理化,默認false禁用 -->

        <!-- 啓用合理化時,如果pageNum<1會查詢第一頁,如果pageNum>pages會查詢最後一頁 -->

        <!-- 禁用合理化時,如果pageNum<1pageNum>pages會返回空數據 -->

        <property name="reasonable" value="true"/>

    </plugin>

</plugins>

這裏的com.github.pagehelper.PageHelper使用完整的類路徑。

其他五個參數說明:

增加dialect屬性,使用時必須指定該屬性,可選值爲oracle,mysql,mariadb,sqlite,hsqldb,postgresql,沒有默認值,必須指定該屬性

增加offsetAsPageNum屬性,默認值爲false,使用默認值時不需要增加該配置,需要設爲true時,需要配置該參數。當該參數設置爲true時,使用RowBounds分頁時,會將offset參數當成pageNum使用,可以用頁碼和頁面大小兩個參數進行分頁。

增加rowBoundsWithCount屬性,默認值爲false,使用默認值時不需要增加該配置,需要設爲true時,需要配置該參數。當該參數設置爲true時,使用RowBounds分頁會進行count查詢。

增加pageSizeZero屬性,默認值爲false,使用默認值時不需要增加該配置,需要設爲true時,需要配置該參數。當該參數設置爲true時,如果pageSize=0或者RowBounds.limit = 0就會查詢出全部的結果(相當於沒有執行分頁查詢,但是返回結果仍然是Page類型)。

增加reasonable屬性,默認值爲false,使用默認值時不需要增加該配置,需要設爲true時,需要配置該參數。具體作用請看上面配置文件中的註釋內容。

如何選擇配置這些參數

單獨看每個參數的說明可能是一件讓人不爽的事情,這裏列舉一些可能會用到某些參數的情況。

首先dialect屬性是必須的,不需要解釋。其他的參數一般情況下我們都不必去管,如果想了解何時使用合適,你可以參考以下場景:

 

場景一

如果你仍然在用類似ibatis式的命名空間調用方式,你也許會用到rowBoundsWithCount,分頁插件對RowBounds支持和Mybatis默認的方式是一致,默認情況下不會進行count查詢,如果你想在分頁查詢時進行count查詢,以及使用更強大的PageInfo類,你需要設置該參數爲true

 

場景二

如果你仍然在用類似ibatis式的命名空間調用方式,你覺得RowBounds中的兩個參數offset,limit不如pageNum,pageSize容易理解,你可以使用offsetAsPageNum參數,將該參數設置爲true後,offset會當成pageNum使用,limitpageSize含義相同。

 

場景三

如果覺得某個地方使用分頁後,你仍然想通過控制參數查詢全部的結果,你可以配置pageSizeZerotrue,配置後,如可以通過設置pageSize=0或者RowBounds.limit = 0就會查詢出全部的結果。

 

場景四

如果你分頁插件使用於類似分頁查看列表式的數據,如新聞列表,軟件列表,你希望用戶輸入的頁數不在合法範圍(第一頁到最後一頁之外)時能夠正確的響應到正確的結果頁面,那麼你可以配置reasonabletrue,這時如果pageNum<1會查詢第一頁,如果pageNum>總頁數會查詢最後一頁。

 

Spring配置方法

首先需要在Spring中配置org.mybatis.spring.SqlSessionFactoryBean。然後配置配置Mybatis的具體配置有兩種方式,一種是用mybatis默認的xml配置,另一種就是完全使用spring的屬性配置方式。

 

 

mybatis默認的xml配置

配置configLocation屬性指向上面的mybatis-config.xml文件。有關分頁插件的配置都在mybatis-config.xml,具體配置內容參考上面的mybatis-config.xml

 

 

使用spring的屬性配置方式

使用spring的屬性配置方式,可以使用plugins屬性像下面這樣配置:

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">

  <property name="dataSource" ref="dataSource"/>

  <property name="mapperLocations">

    <array>

      <value>classpath:mapper/*.xml</value>

    </array>

  </property>

  <property name="typeAliasesPackage" value="com.isea533.ssm.model"/>

  <property name="plugins">

    <array>

      <bean class="com.github.pagehelper.PageHelper">

        <property name="properties">

          <value>

            dialect=hsqldb

            reasonable=true

          </value>

        </property>

      </bean>

    </array>

  </property>

</bean>

屬性配置按照上面的方式配置,每個配置獨立一行即可。

 

如何在代碼中使用

閱讀前後請注意看重要提示

首先該分頁插件支持以下兩種調用方式:

//第一種,RowBounds方式的調用

List<Country> list = sqlSession.selectList("x.y.selectIf", null, new RowBounds(1, 10));

 

//第二種,Mapper接口方式的調用,推薦這種使用方式。

PageHelper.startPage(1, 10);

List<Country> list = countryMapper.selectIf(1);

下面分別對這兩種方式進行詳細介紹

 

RowBounds方式的調用

List<Country> list = sqlSession.selectList("x.y.selectIf", null, new RowBounds(1, 10));

使用這種調用方式時,你可以使用RowBounds參數進行分頁,這種方式侵入性最小,我們可以看到,通過RowBounds方式調用只是使用了這個參數,並沒有增加其他任何內容。

分頁插件檢測到使用了RowBounds參數時,就會對該查詢進行物理分頁

關於這種方式的調用,有兩個特殊的參數是針對RowBounds的,你可以參看上面的場景一場景二

注:不只有命名空間方式可以用RowBounds,使用接口的時候也可以增加RowBounds參數,例如:

//這種情況下也會進行物理分頁查詢

List<Country> selectAll(RowBounds rowBounds); 

 

 

PageHelper.startPage靜態方法調用

在你需要進行分頁的Mybatis方法前調用PageHelper.startPage靜態方法即可,緊跟在這個方法後的第一個Mybatis查詢方法會被進行分頁。

 

例一:

SqlSession sqlSession = MybatisHelper.getSqlSession();

CountryMapper countryMapper = sqlSession.getMapper(CountryMapper.class);

try {

    //獲取第1頁,10條內容,默認查詢總數count

    PageHelper.startPage(1, 10);

 

    //緊跟着的第一個select方法會被分頁

    List<Country> list = countryMapper.selectIf(1);

    assertEquals(2, list.get(0).getId());

    assertEquals(10, list.size());

    //分頁時,實際返回的結果list類型是Page<E>,如果想取出分頁信息,需要強制轉換爲Page<E>

    //或者使用PageInfo類(下面的例子有介紹)

    assertEquals(182, ((Page) list).getTotal());

} finally {

    sqlSession.close();

}

 

例二:

SqlSession sqlSession = MybatisHelper.getSqlSession();

CountryMapper countryMapper = sqlSession.getMapper(CountryMapper.class);

try {

    //獲取第1頁,10條內容,默認查詢總數count

    PageHelper.startPage(1, 10);

 

    //緊跟着的第一個select方法會被分頁

    List<Country> list = countryMapper.selectIf(1);

 

    //後面的不會被分頁,除非再次調用PageHelper.startPage

    List<Country> list2 = countryMapper.selectIf(null);

    //list1

    assertEquals(2, list.get(0).getId());

    assertEquals(10, list.size());

    //分頁時,實際返回的結果list類型是Page<E>,如果想取出分頁信息,需要強制轉換爲Page<E>

    //或者使用PageInfo類(下面的例子有介紹)

    assertEquals(182, ((Page) list).getTotal());

    //list2

    assertEquals(1, list2.get(0).getId());

    assertEquals(182, list2.size());

} finally {

    sqlSession.close();

}

 

 

例三,使用PageInfo的用法:

//獲取第1頁,10條內容,默認查詢總數count

PageHelper.startPage(1, 10);

List<Country> list = countryMapper.selectAll();

//PageInfo對結果進行包裝

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());

本項目中包含大量測試,您可以通過查看測試代碼瞭解使用方法。

測試代碼地址:http://git.oschina.net/free/Mybatis_PageHelper/tree/master/src/test/java/com/github/pagehelper/test

 

重要提示

PageHelper.startPage方法重要提示

只有緊跟在PageHelper.startPage方法後的第一個Mybatis查詢(Select方法)方法會被分頁。

 

 

分頁插件不支持帶有for update語句的分頁

對於帶有for updatesql,會拋出運行時異常,對於這樣的sql建議手動分頁,畢竟這樣的sql需要重視。

 

 

分頁插件不支持關聯結果查詢

原因以及解決方法可以看這裏:

http://my.oschina.net/flags/blog/274000

分支插件不支持關聯結果查詢,但是支持關聯嵌套查詢。只會對主sql進行分頁,嵌套的sql不會被分頁。

 

 

 

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