1. 程式人生 > >JavaWeb從新手到入門(四)Spring Mybatis使用pageHelper實現物理分頁

JavaWeb從新手到入門(四)Spring Mybatis使用pageHelper實現物理分頁

一、分頁

對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具備分頁特性(只有緊接著的下一句才有效)。

執行結果發現已經達到了分頁的目的: