Java開發中,通過sql來實現過濾以及分頁
我們通過一個需求來引入問題。
首先,簡單介紹一下需求:實現一個下圖的頁面,包含了過濾以及分頁。資料是後臺資料庫獲得到的。
那麼關於如何實現過濾以及分頁,考慮到通過前臺實現或者後臺實現,我們不妨來分析一下兩種方法。
首先,前臺實現:無非就是後臺獲取所有的list,傳給前臺暫存,然後前臺按照使用者的過濾或者分頁,來處理list,展示給前臺。
後臺實現:前臺要什麼過濾,要第幾頁,我們就返回什麼list。
那麼在我看來,前臺實現劣勢有三:
1. 傳輸問題:現在開發過程資料庫中的案例數很少,十幾個案例沒啥問題。可是當資料庫中案例數增加後,幾百甚至幾千條的資料同時傳輸,傳輸速率肯定有所降低,前臺載入一個頁面可能要很久,使用者體驗極差。
2. 記憶體佔用問題:同樣是 當資料量過大時,不論後臺還是前臺,都需要一大片空間來儲存,佔據大量記憶體。其中又有很多是暫時用不上的資料,造成資源浪費。
3. 時效性問題:我們舉個例子,按照後臺一次性獲取所有案例給前臺,而這個獲取過程可能是通過外部的一個點選事件觸發,如果此時有使用者對案例進行了修改,那麼不論是翻頁還是過濾,都看不出來使用者的修改。而如果每次過濾或者翻頁都是即時的從後臺獲取,就可以保證每次過濾或者分頁都是最新的內容。
當然這只是我所認為分析出來的前臺實現劣勢,如果有什麼前臺的優化方法還請指出:)
====================================================================
所以接下來我們就考慮利用後臺來進行實現,那麼思考一下,前臺告訴我們對哪些欄位進行過濾,進行怎樣的分頁(每頁有幾個案例,第幾頁),然後我們根據這些引數來實現過濾或者分頁。
最直接的方法,還是資料庫直接獲取所有案例,然後按照欄位篩選,按照分頁條件篩選。咦?直接獲取的資料又不是我全都要,這樣不還是佔用了很多記憶體。那怎麼辦呢,我們不妨從資料庫訪問過程入手,通過sql來實現過濾分頁呢。
那麼就有了下面的方法: 關於過濾,前臺傳給我們一個包含過濾欄位以及過濾欄位關鍵字的json就可以啦,如下的<if></if>,判斷對應欄位是否存在,如果存在,那就利用like進行過濾
<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;
}