1. 程式人生 > >SpringMVCDemo中,遇到的問題(四) 之分頁功能

SpringMVCDemo中,遇到的問題(四) 之分頁功能

1、背景:

  線上經常出現因為研發程式碼編寫不規範,sql語句全表查詢,資料過多,硬生生把記憶體塞爆不斷GC,整個服務宕掉的情況。

  引發這種場景的原因之一,歸咎在使用mybatis編寫sql語句時使用了萬能查詢語句。where 1=1之後,拼接的if條件都不符合條件。如下:

  如果下面sql語句中,if條件都匹配不上,最後會執行  select * from retailer where 1=1

 1     <!--sql片段-->
 2     <sql id="query_retailer_where">
 3         <
if test="name!=null">and name like '%${name}%'</if> 4 <if test="address!=null">and address like '%${address}%'</if> 5 <if test="status!=null">and status like '%${status}%'</if> 6 <if test="telphone!=null">and telphone = #{telphone}</if
> 7 <if test="createtime!=null"> 8 and createtime = DATE_FORMAT(#{createtime},'%Y-%m-%d %H:%i:%S') 9 </if> 10 <if test="starttime != null"> <![CDATA[ and createtime >= to_date(#{starttime},'yyyy-MM-dd HH:mm:ss')]]></if> 11 <
if test="endtime != null"> <![CDATA[ and createtime <= to_date(#{endtime},'yyyy-MM-dd HH:mm:ss')]]></if> 12 </sql> 13 14 <!--查詢--> 15 <select id="find" resultMap="resultMap" parameterType="java.util.Map"> 16 select * from retailer 17 where 1=1 18 <include refid="query_retailer_where"></include> 19 <if test="startPage != null and pageSize !=null"> 20 order by createtime desc 21 -- LIMIT #{startPage},#{pageSize} 22 </if> 23 </select>

 這類場景的解決辦法,

 一種是使用<choose></choose>,如果匹配不到就查詢不到,或查詢個預設範圍。

<where>
    <choose>
        <when>
        </when>
        <otherwise>
             AND 1=0
        </otherwise>  
   </choose>
</where>

另外一種就是使用分頁查詢,引入Limit,限制查詢出的資料條數。

2、使用思路:

    <!--查詢-->
    <select id="find" resultMap="resultMap" parameterType="java.util.Map">
        select * from retailer
        where 1=1
        <include refid="query_retailer_where"></include>
        <if test="startPage != null and pageSize !=null">
            order by createtime desc
            LIMIT #{startPage},#{pageSize}
        </if>
    </select>

由底向上的思路,從limit的使用,來考慮一下傳值的邏輯。

limit的語法是,select * from table where ... limit start,size;

  start:從第幾條記錄開始。

  size : 讀取幾條記錄。

首先需要知道,從第幾條[下標]開始讀,要往後讀取多少條。

即分頁顯示的話,需要傳給sql語句兩個引數,某一頁面中第一條在表中的下標,以及頁面中資料的條數。

size好說,預設指定一個,或者從前臺輸入後取一個。

start下標,

  一種方式是,前端js計算完,直接傳值過來。不涉及sql語句的計算。

  另一種方式是,前端傳過來要跳轉到的頁碼,後臺sql中加入(pageNum-1)*size的計算,即為對應頁面的start下標值。

3、實現:

以第一種為例。

 1)編寫分頁查詢的PageEntity類,首次查詢列表,需要給定個預設值

/**
 * 分頁類,包含三個屬性
 * 開始頁面、起始資料位置、每頁要取的資料
 */
public class PageEntity {

    //當前頁
    private Integer currentPage;
    //起始頁
    private Integer startPage;
    //頁面的資料大小
    private Integer pageSize;

    public Integer getCurrentPage() {
        if(currentPage==null){
            currentPage = 1;
        }
        return currentPage;
    }

    public void setCurrentPage(Integer currentPage) {
        this.currentPage = currentPage;
    }

    public Integer getStartPage() {
        if (startPage==null){
            startPage=0;
        }
        return startPage;
    }

    public void setStartPage(Integer startPage) {
        this.startPage = startPage;
    }

    public Integer getPageSize() {
        if (pageSize==null){
            pageSize=5;
        }
        return pageSize;
    }

    public void setPageSize(Integer pageSize) {
        this.pageSize = pageSize;
    }
}