JavaWeb從新手到入門(四)Spring Mybatis使用pageHelper實現物理分頁
阿新 • • 發佈:2018-12-25
一、分頁
對JavaWeb來說,分頁是十分常見的一種需求,一般來說資料的專案大於單次可顯示的條目,因此當查詢時需要對查詢得到的結果進行分頁顯示。
二、MyBtais分頁方法的分類
Mybatis被稱為半自動化的ORM框架,因為相比hibernate而言,其對SQL操作的遮蔽更加淺層表面,Mybatis將SQL操作提取並容納於Mapper.xml檔案中,新新增的操作需要使用者寫出SQL語句,因此對於分頁是功能較弱。
MyBatis分頁的方法按照SQL的執行方式來分為兩種:
1. 記憶體分頁,也就是假分頁。本質是查出所有的資料然後根據遊標的方式擷取需要的記錄。如果資料量大,開銷大和記憶體溢位。
2. 物理分頁 ,也就是查詢執行的SQL語句為新增分頁指令後的語句,這種情況下Mybatis的分頁不再是系統的效能瓶頸。
按照實現方式來說,物理分頁又可以分為自定義SQL和實現攔截器兩種,下面分別介紹記憶體分頁和物理分頁的實現方法。
三、MyBatis分頁方法的實現
3.1 記憶體分頁
優點:實現簡單,不需要新增額外程式碼
缺點:大資料情況下效能差。
記憶體分頁的實現通過利用自動生成的example類,加入mybatis的RowBounds類,在呼叫的介面中新增給類的引數,示例程式碼如下:
1. 新增rowBounds引數
@RequestMapping("/itemlist1/{pageNum}") @ResponseBody private List<TbItem> getItemBypage1(@PathVariable Integer pageNum){ TbItemExample example = new TbItemExample(); RowBounds rowBounds = new RowBounds(0, 5); TbItemExample.Criteria criteria = example.createCriteria(); example.setOrderByClause("Id desc");//設定排序方式 return itemMapper.selectByExampleEx(example, rowBounds); }
2. 實現冗餘查詢方法
此處的selectByExampleEx為自定義方法,與selectByExample一致(傳入的RowBounds引數由Mybatis自行處理,不需要在SQL語句中做出反應)。
List<TbItem> selectByExampleEx(TbItemExample example, RowBounds rowBounds);
這樣實現的分頁在大資料情況下需要查詢出所有結果後進行擷取,因此效能較差,不常使用。<select id="selectByExampleEx" resultMap="BaseResultMap" > select <if test="distinct" > distinct </if> <include refid="Base_Column_List" /> from tb_item_param <if test="_parameter != null" > <include refid="Example_Where_Clause" /> </if> <if test="orderByClause != null" > order by ${orderByClause} </if> </select>
3.2 自定義SQL
優點:SQL查詢效率優化餘地大,使用方便
缺點:要為每一個需要分頁特性的類新增程式碼,工作量大且不靈活
自定義SQL的實現需要在真正執行的SQL語句上修改,使傳入的引數中增加分頁上下限的功能,本次採用修改Example物件的方法進行1.修改Example物件
public class TbItemExample {
protected String orderByClause;
protected boolean distinct;
public int start;
public int limit;
public int getStart() { return start;}
public void setStart(int start) { this.start = start;}
public int getLimit() { return limit;}
public void setLimit(int limit) { this.limit = limit;}
...
}
2. 修改SQL語句
新增Start和limit屬性後對selectByExample語句對應的SQL語句進行修改:<select id="selectByExample" resultMap="BaseResultMap" parameterType="priv.ality.pojo.TbItemExample" >
select
<if test="distinct" >
distinct
</if>
<include refid="Base_Column_List" />
from tb_item
<if test="_parameter != null" >
<include refid="Example_Where_Clause" />
</if>
<if test="orderByClause != null" >
order by ${orderByClause}
</if>
<if test="start !=0 or limit!=0">
limit #{start},#{limit}
</if>
</select>
3. 新增查詢屬性
添加了start和limit不為0時的分頁處理,確保分頁正確完成,使用時在Controller中設定屬性即可:@RequestMapping("/itemlist2/{pageNum}")
@ResponseBody
private List<TbItem> getItemBypage2(@PathVariable Integer pageNum){
TbItemExample example = new TbItemExample();
example.setStart(0);
example.setLimit(5);
example.setOrderByClause("Id desc");//設定排序方式
return itemMapper.selectByExample(example);
}
查詢能夠達到預期效果:
3.3 攔截器
優點:使用方便,不存在分頁上額外的效能瓶頸。
缺點:引入開源庫干擾專案的穩定性,效能難以優化。
Mybatis中使用的攔截器可以類比Spring中的AOP概念,通過攔截器獲取SQL語句,然後對SQL語句進行修改之後再進行下一步查詢,這樣的方法使使用者使用起來更加簡潔清晰,但是也需要注意,這樣的話SQL優化就只能依靠封裝的開源庫的內部實現了(畢竟SQL語句修改的地方被開源庫隔離了)。常用的開源庫是pageHleper,專案地址:Mybatis_PageHelper外掛的使用分為如下的步驟:
1. 在POM中引入依賴:
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>3.7.5</version>
</dependency>
作者是個很勤奮的人,目前已經更新到5.x,本部落格中使用了3.7.5無誤,其餘需要摸索下(5.x之後主類名和引數定義發生變化)。
2. 在Spring-mybatis配置檔案中新增外掛
<!-- mybatis和spring完美整合,不需要mybatis的配置對映檔案 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!-- 自動掃描mapping.xml檔案 -->
<property name="mapperLocations" value="classpath:mapping/*.xml"></property>
<!-- MybatisSpringPageInterceptor分頁攔截器 -->
<property name="plugins">
<array>
<bean class="com.github.pagehelper.PageHelper">
<property name="properties">
<value>
<!-- 設定資料庫型別 Oracle,Mysql,MariaDB,SQLite,Hsqldb,PostgreSQL六種資料庫-->
<property name="dialect" value="mysql"/>
</value>
</property>
</bean>
</array>
</property>
</bean>
由於本例中將mybatis與Spring整合到了一起,所以pageHelper的依賴以bean的方式配置在Spring中,外掛還提供了作為Mybatis配置的一種方式。配置中主要的依賴項參見作者說明:使用方法
3. 在使用處新增開始程式碼
在Controller中新增程式碼如下:
@RequestMapping("/itemlist/{pageNum}")
@ResponseBody
private List<TbItem> getItemByPage(@PathVariable Integer pageNum) {
PageHelper.startPage(pageNum,10);
TbItemExample example = new TbItemExample();
List<TbItem> list = itemMapper.selectByExample(example);
return list;
}
其中PageHelper.startPage(pageNum,10);指定下一句執行的SQL具備分頁特性(只有緊接著的下一句才有效)。
執行結果發現已經達到了分頁的目的: