1. 程式人生 > >Java開發中,通過sql來實現過濾以及分頁

Java開發中,通過sql來實現過濾以及分頁

 

我們通過一個需求來引入問題。

首先,簡單介紹一下需求:實現一個下圖的頁面,包含了過濾以及分頁。資料是後臺資料庫獲得到的。

那麼關於如何實現過濾以及分頁,考慮到通過前臺實現或者後臺實現,我們不妨來分析一下兩種方法。

首先,前臺實現:無非就是後臺獲取所有的list,傳給前臺暫存,然後前臺按照使用者的過濾或者分頁,來處理list,展示給前臺。

後臺實現:前臺要什麼過濾,要第幾頁,我們就返回什麼list。

那麼在我看來,前臺實現劣勢有三

1. 傳輸問題:現在開發過程資料庫中的案例數很少,十幾個案例沒啥問題。可是當資料庫中案例數增加後,幾百甚至幾千條的資料同時傳輸,傳輸速率肯定有所降低,前臺載入一個頁面可能要很久,使用者體驗極差。

2. 記憶體佔用問題:同樣是 當資料量過大時,不論後臺還是前臺,都需要一大片空間來儲存,佔據大量記憶體。其中又有很多是暫時用不上的資料,造成資源浪費。

3. 時效性問題:我們舉個例子,按照後臺一次性獲取所有案例給前臺,而這個獲取過程可能是通過外部的一個點選事件觸發,如果此時有使用者對案例進行了修改,那麼不論是翻頁還是過濾,都看不出來使用者的修改。而如果每次過濾或者翻頁都是即時的從後臺獲取,就可以保證每次過濾或者分頁都是最新的內容。

當然這只是我所認為分析出來的前臺實現劣勢,如果有什麼前臺的優化方法還請指出:)

====================================================================

所以接下來我們就考慮利用後臺來進行實現,那麼思考一下,前臺告訴我們對哪些欄位進行過濾,進行怎樣的分頁(每頁有幾個案例,第幾頁),然後我們根據這些引數來實現過濾或者分頁。

最直接的方法,還是資料庫直接獲取所有案例,然後按照欄位篩選,按照分頁條件篩選。咦?直接獲取的資料又不是我全都要,這樣不還是佔用了很多記憶體。那怎麼辦呢,我們不妨從資料庫訪問過程入手,通過sql來實現過濾分頁呢。

那麼就有了下面的方法: 關於過濾,前臺傳給我們一個包含過濾欄位以及過濾欄位關鍵字的json就可以啦,如下的<if></if>,判斷對應欄位是否存在,如果存在,那就利用like進行過濾

。(程式碼使用Mybatis作為持久層框架,所以程式碼直接貼啦)

<select id="getCaseView" resultType="com.common.bean.CaseInfo">
		select id, type, title, create_user as user, status
		    from t_tbl_case_info where
		<choose>
			<when test="tableBaseRequest.filter.viewType==0">
				status = '3'
			</when>
			<when test="tableBaseRequest.filter.viewType==1">
				status != '4' and create_user = #{curUser}
			</when>
		</choose>
		<if test="tableBaseRequest.filter.title!=null">
			and title like concat('%',#{tableBaseRequest.filter.title},'%')
		</if>
		<if test="tableBaseRequest.filter.type!=null">
			and type in 
			<foreach collection="tableBaseRequest.filter.type" item="item"
				open="(" separator="," close=")">
				#{item}
			</foreach>
		</if>
		<if test="tableBaseRequest.filter.user!=null">
			and user like concat('%',#{tableBaseRequest.filter.user},'%')
		</if>
		order by create_time desc
		limit #{tableBaseRequest.offset}, #{tableBaseRequest.pageSize}
	</select>

 

關於分頁,可以看到實現在sql的最後,limit #{tableBaseRequest.offset}, #{tableBaseRequest.pageSize},使用limit即可,在一個經過計算的偏移量offset之後,選擇 一頁展示的資料,offset可以前臺計算傳到後臺,也可以前臺只傳頁碼以及一頁中案例數量 後臺來計算。

tableBaseRequest.setOffset((tableBaseRequest.getCurPage() - 1) * tableBaseRequest.getPageSize())

如此一來,前臺實現傳遞過濾欄位以及過濾內容、頁碼以及每頁條數,便可以完成通過sql來在後臺實現過濾以及分頁

附一下前臺傳遞的引數,一個自定義類

public class TableBaseRequest
{
    /**
     * 表格分頁資訊,當前是第幾頁
     */
    @Min(1)
    @Max(Integer.MAX_VALUE)
    private int curPage;
    
    /**
     * 表格分頁資訊,每頁展示多少條資料
     */
    @IntPattern(regexp = ValidatorConstants.TABLE_PAGESIZE_REGEXP)
    private int pageSize;
    
    /**
     * 表格分頁資訊,查詢資料庫的偏移量
     */
    private int offset;
    
    /**
     * 過濾引數 filter:{ "text":"XXX", "select":["0", "1"], "time":{"startTime":"2018-02-01 00:00:00", "endTime":
     * "2018-02-02 23:59:59"} }
     */
    private JSONObject filter;


    /**
     * 排序列,如不為空即需要對此欄位進行排序
     */
    @Length(max = 100)
    private String sortName;
    
    /**
     * 排序型別,預設desc,列舉包括:增序asc或降序desc
     */
    @Pattern(regexp = ValidatorConstants.TABLE_SORT_REGEXP)
    private String sortValue;
}