Mybatis分頁插件-PageHepler的使用
使用方法
1. 引入分頁插件
引入分頁插件一共有下面2種方式,推薦使用Maven方式,這種方式方便更新。
1). 引入Jar包
如果你想使用本項(xiàng)目的jar包而不是直接引入類,你可以在這里下載各個(gè)版本的jar包(點(diǎn)擊Download下的jar即可下載)
https://oss.sonatype.org/content/repositories/releases/com/github/pagehelper/pagehelper/
http://repo1.maven.org/maven2/com/github/pagehelper/pagehelper/
由于使用了sql解析工具,你還需要下載jsqlparser.jar(這個(gè)文件完全獨(dú)立,不依賴其他):
2). 使用maven
添加如下依賴:
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>3.6.4</version>
</dependency>
當(dāng)使用maven中央庫中的快照版(帶"-SNAPSHOT"的版本)時(shí),需要在pom.xml中添加如下配置:
<repositories>
<repository>
<id>sonatype-nexus-snapshots</id>
<name>Sonatype Nexus Snapshots</name>
<url>http://oss.sonatype.org/content/repositories/snapshots</url>
<releases>
<enabled>false</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
2. 在Mybatis配置xml中配置攔截器插件:
<!--
plugins在配置文件中的位置必須符合要求,否則會(huì)報(bào)錯(cuò),順序如下:
properties?, settings?,
typeAliases?, typeHandlers?,
objectFactory?,objectWrapperFactory?,
plugins?,
environments?, databaseIdProvider?, mappers?
-->
<plugins>
<!-- com.github.pagehelper為PageHelper類所在包名 -->
<plugin interceptor="com.github.pagehelper.PageHelper">
<property name="dialect" 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"/>
<!-- 3.3.0版本可用 - 分頁參數(shù)合理化,默認(rèn)false禁用 -->
<!-- 啟用合理化時(shí),如果pageNum<1會(huì)查詢第一頁,如果pageNum>pages會(huì)查詢最后一頁 -->
<!-- 禁用合理化時(shí),如果pageNum<1或pageNum>pages會(huì)返回空數(shù)據(jù) -->
<property name="reasonable" value="true"/>
<!-- 3.5.0版本可用 - 為了支持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>
這里的com.github.pagehelper.PageHelper使用完整的類路徑。
其他五個(gè)參數(shù)說明:
增加
dialect屬性,使用時(shí)必須指定該屬性,可選值為oracle,mysql,mariadb,sqlite,hsqldb,postgresql,sqlserver,沒有默認(rèn)值,必須指定該屬性。增加
offsetAsPageNum屬性,默認(rèn)值為false,使用默認(rèn)值時(shí)不需要增加該配置,需要設(shè)為true時(shí),需要配置該參數(shù)。當(dāng)該參數(shù)設(shè)置為true時(shí),使用RowBounds分頁時(shí),會(huì)將offset參數(shù)當(dāng)成pageNum使用,可以用頁碼和頁面大小兩個(gè)參數(shù)進(jìn)行分頁。增加
rowBoundsWithCount屬性,默認(rèn)值為false,使用默認(rèn)值時(shí)不需要增加該配置,需要設(shè)為true時(shí),需要配置該參數(shù)。當(dāng)該參數(shù)設(shè)置為true時(shí),使用RowBounds分頁會(huì)進(jìn)行count查詢。增加
pageSizeZero屬性,默認(rèn)值為false,使用默認(rèn)值時(shí)不需要增加該配置,需要設(shè)為true時(shí),需要配置該參數(shù)。當(dāng)該參數(shù)設(shè)置為true時(shí),如果pageSize=0或者RowBounds.limit = 0就會(huì)查詢出全部的結(jié)果(相當(dāng)于沒有執(zhí)行分頁查詢,但是返回結(jié)果仍然是Page類型)。增加
reasonable屬性,默認(rèn)值為false,使用默認(rèn)值時(shí)不需要增加該配置,需要設(shè)為true時(shí),需要配置該參數(shù)。具體作用請(qǐng)看上面配置文件中的注釋內(nèi)容。為了支持
startPage(Object params)方法,增加了一個(gè)params參數(shù)來配置參數(shù)映射,用于從Map或ServletRequest中取值,可以配置pageNum,pageSize,count,pageSizeZero,reasonable,不配置映射的用默認(rèn)值。
重要提示:
當(dāng)offsetAsPageNum=false的時(shí)候,由于PageNum問題,RowBounds查詢的時(shí)候reasonable會(huì)強(qiáng)制為false。使用PageHelper.startPage方法不受影響。
另外使用RowBounds在這種情況下返回的Page對(duì)象由于沒有正確的pageNum屬性,所以也不能使用PageInfo處理。
如果你不理解為什么,可以看這樣一個(gè)例子:查詢offset=7,limit=10,這個(gè)時(shí)候pageNum=?,這種情況沒法計(jì)算pageNum,沒法判斷當(dāng)前是第幾頁。
3. 如何選擇配置這些參數(shù)
單獨(dú)看每個(gè)參數(shù)的說明可能是一件讓人不爽的事情,這里列舉一些可能會(huì)用到某些參數(shù)的情況。
首先dialect屬性是必須的,不需要解釋。其他的參數(shù)一般情況下我們都不必去管,如果想了解何時(shí)使用合適,你可以參考以下場(chǎng)景:
場(chǎng)景一
如果你仍然在用類似ibatis式的命名空間調(diào)用方式,你也許會(huì)用到rowBoundsWithCount,分頁插件對(duì)RowBounds支持和Mybatis默認(rèn)的方式是一致,默認(rèn)情況下不會(huì)進(jìn)行count查詢,如果你想在分頁查詢時(shí)進(jìn)行count查詢,以及使用更強(qiáng)大的PageInfo類,你需要設(shè)置該參數(shù)為true。
場(chǎng)景二
如果你仍然在用類似ibatis式的命名空間調(diào)用方式,你覺得RowBounds中的兩個(gè)參數(shù)offset,limit不如pageNum,pageSize容易理解,你可以使用offsetAsPageNum參數(shù),將該參數(shù)設(shè)置為true后,offset會(huì)當(dāng)成pageNum使用,limit和pageSize含義相同。
場(chǎng)景三
如果覺得某個(gè)地方使用分頁后,你仍然想通過控制參數(shù)查詢?nèi)康慕Y(jié)果,你可以配置pageSizeZero為true,配置后,如可以通過設(shè)置pageSize=0或者RowBounds.limit = 0就會(huì)查詢出全部的結(jié)果。
場(chǎng)景四
如果你分頁插件使用于類似分頁查看列表式的數(shù)據(jù),如新聞列表,軟件列表,你希望用戶輸入的頁數(shù)不在合法范圍(第一頁到最后一頁之外)時(shí)能夠正確的響應(yīng)到正確的結(jié)果頁面,那么你可以配置reasonable為true,這時(shí)如果pageNum<1會(huì)查詢第一頁,如果pageNum>總頁數(shù)會(huì)查詢最后一頁。
4. Spring配置方法
首先需要在Spring中配置org.mybatis.spring.SqlSessionFactoryBean。然后配置配置Mybatis的具體配置有兩種方式,一種是用mybatis默認(rèn)的xml配置,另一種就是完全使用spring的屬性配置方式。
1.mybatis默認(rèn)的xml配置
配置configLocation屬性指向上面的mybatis-config.xml文件。有關(guān)分頁插件的配置都在mybatis-config.xml,具體配置內(nèi)容參考上面的mybatis-config.xml。
2.使用spring的屬性配置方式
注意:請(qǐng)不用同時(shí)使用spring配置方式和mybatis-config.xml配置方式,只需要選擇其中一個(gè)就行。配置多個(gè)分頁插件時(shí),會(huì)拋出異常提示。
分頁插件配置錯(cuò)誤:請(qǐng)不要在系統(tǒng)中配置多個(gè)分頁插件(使用Spring時(shí),mybatis-config.xml和Spring配置方式,請(qǐng)選擇其中一種,不要同時(shí)配置多個(gè)分頁插件)!
使用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>
屬性配置按照上面的方式配置,每個(gè)配置獨(dú)立一行即可。
5. 如何在代碼中使用
閱讀前后請(qǐng)注意看重要提示
首先該分頁插件支持以下兩種調(diào)用方式:
//第一種,RowBounds方式的調(diào)用
List<Country> list = sqlSession.selectList("x.y.selectIf", null, new RowBounds(1, 10));
//第二種,Mapper接口方式的調(diào)用,推薦這種使用方式。
PageHelper.startPage(1, 10);
List<Country> list = countryMapper.selectIf(1);
下面分別對(duì)這兩種方式進(jìn)行詳細(xì)介紹
1). RowBounds方式的調(diào)用
List<Country> list = sqlSession.selectList("x.y.selectIf", null, new RowBounds(1, 10));
使用這種調(diào)用方式時(shí),你可以使用RowBounds參數(shù)進(jìn)行分頁,這種方式侵入性最小,我們可以看到,通過RowBounds方式調(diào)用只是使用了這個(gè)參數(shù),并沒有增加其他任何內(nèi)容。
分頁插件檢測(cè)到使用了RowBounds參數(shù)時(shí),就會(huì)對(duì)該查詢進(jìn)行物理分頁。
關(guān)于這種方式的調(diào)用,有兩個(gè)特殊的參數(shù)是針對(duì)RowBounds的,你可以參看上面的場(chǎng)景一和場(chǎng)景二
注:不只有命名空間方式可以用RowBounds,使用接口的時(shí)候也可以增加RowBounds參數(shù),例如:
//這種情況下也會(huì)進(jìn)行物理分頁查詢
List<Country> selectAll(RowBounds rowBounds);
2). PageHelper.startPage靜態(tài)方法調(diào)用
在你需要進(jìn)行分頁的Mybatis方法前調(diào)用PageHelper.startPage靜態(tài)方法即可,緊跟在這個(gè)方法后的第一個(gè)Mybatis查詢方法會(huì)被進(jìn)行分頁。
例一:
SqlSession sqlSession = MybatisHelper.getSqlSession();
CountryMapper countryMapper = sqlSession.getMapper(CountryMapper.class);
try {
//獲取第1頁,10條內(nèi)容,默認(rèn)查詢總數(shù)count
PageHelper.startPage(1, 10);
//緊跟著的第一個(gè)select方法會(huì)被分頁
List<Country> list = countryMapper.selectIf(1);
assertEquals(2, list.get(0).getId());
assertEquals(10, list.size());
//分頁時(shí),實(shí)際返回的結(jié)果list類型是Page<E>,如果想取出分頁信息,需要強(qiáng)制轉(zhuǎn)換為Page<E>,
//或者使用PageInfo類(下面的例子有介紹)
assertEquals(182, ((Page) list).getTotal());
} finally {
sqlSession.close();
}
例二:
SqlSession sqlSession = MybatisHelper.getSqlSession();
CountryMapper countryMapper = sqlSession.getMapper(CountryMapper.class);
try {
//獲取第1頁,10條內(nèi)容,默認(rèn)查詢總數(shù)count
PageHelper.startPage(1, 10);
//緊跟著的第一個(gè)select方法會(huì)被分頁
List<Country> list = countryMapper.selectIf(1);
//后面的不會(huì)被分頁,除非再次調(diào)用PageHelper.startPage
List<Country> list2 = countryMapper.selectIf(null);
//list1
assertEquals(2, list.get(0).getId());
assertEquals(10, list.size());
//分頁時(shí),實(shí)際返回的結(jié)果list類型是Page<E>,如果想取出分頁信息,需要強(qiáng)制轉(zhuǎn)換為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條內(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);
//測(cè)試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());