學會改變自己——才能突破
分頁查詢,就是將將過多的結果在有限的介面上分好多頁來顯示,這個是很多網站常用的功能,也是最基本的功能,今天簡單總結一下。
分頁以前聽人們說都是一項技術,但是我覺的不盡然。我認為分頁是將資料庫的資料,利用一些特殊的sql語句來進行查詢,顯示理所應當顯示的內容,更恰當的說可以是對SQL語句的靈活運用,對邏輯思維的簡單使用。
一,一般人們將分頁查詢分為兩類:邏輯分頁,物理分頁,我們先從理論上理解一下:
1,邏輯分頁概述:就是使用者第一次訪問時,將資料庫的所有記錄全部查詢出來,新增到一個大的集合中,然後存放在session物件,然後通過頁碼計算出當前頁需要顯示的資料內容,儲存到一個小的
來看它的一些缺點吧:
a,如果需要查詢的資料量過大,session將耗費大量的記憶體;
b,因為是在session中獲取資料,如果第二次或者更多此的不關閉瀏覽器訪問,會直接訪問session,從而不能保證資料是最新的。
小結:這種分頁很少使用。但是在資料量小,不會被修改的資料,使用邏輯分頁會提高程式的執行效率。
2,物理分頁概述:使用資料庫自身所帶的分頁機制,例如,Oracle資料庫的rownum,或者Mysql資料庫中的limit等機制來完成分頁操作。因為是對資料庫實實在在的資料進行分頁條件查詢,所以叫物理分頁。每一次物理分頁都會去連線資料庫。
優點:資料能夠保證最新,由於根據分頁條件會查詢出少量的資料,所以不會佔用太多的記憶體。
缺點:物理分頁使用了資料庫自身帶的機制,所以這樣的SQL語句不通用,導致不能進行資料庫的移植。
小結:在實際中物理分頁還是使用的較多的。
二,看一下邏輯分頁查詢的應用:
public class PageQueryUserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//獲取頁碼
int pageno = Integer.parseInt(request.getParameter("pageno")==null?"1":request.getParameter("pageno"));
//從session中獲取大List集合
HttpSession session = request.getSession();
List<User> bigList = (List<User>)session.getAttribute("bigList");
//如果第一次訪問
if(bigList == null){
//建立大List集合
bigList = new ArrayList<User>();
//如果大List集合不存在,則連線資料庫
Connection conn = null;
PreparedStatement ps= null;
ResultSet rs = null;
try {
conn = DBUtil.getConnection();
String sql = "select usercode,username,orgtype from t_user order by regdate desc";
ps = conn.prepareStatement(sql);
//執行查詢語句返回查詢結果集
rs = ps.executeQuery();
//遍歷結果集封裝javabean物件並存儲到大List集合中
while(rs.next()){
User user = new User();
user.setUsercode(rs.getString("usercode"));
user.setUsername(rs.getString("username"));
user.setOrgtype(rs.getString("orgtype"));
bigList.add(user);
}
//將大List集合儲存到session中
session.setAttribute("bigList", bigList);
} catch (Exception e) {
e.printStackTrace();
} finally{
DBUtil.close(conn, ps, rs);
}
}
//如果從session中可以獲取到大List集合,則通過頁碼計算得出小List集合
List<User> smallList = new ArrayList<User>();
//計算開始標識=頁數大小*(頁碼-1)
int beginIndex = Const.PAGE_SIZE * (pageno-1);
//結束標識=頁數大小*頁碼,如果超過了總資料條數,則表示為最後一頁,寫為總結條數即可
int endIndex = Const.PAGE_SIZE * pageno > bigList.size() ? bigList.size() : Const.PAGE_SIZE * pageno;
for(int i=beginIndex;i<endIndex;i++){
smallList.add(bigList.get(i));
}
//將小List集合儲存到request物件中
request.setAttribute("userList", smallList);
//轉發
}
}
三,好,物理分頁和邏輯分頁的計算方法差不多,只不過一個是session中一個是在資料庫中,這裡物理分頁總結一下多條件查詢分頁顯示的過程,這裡也將分頁物件進行封裝了:
先看一下分頁物件的編寫:
/**
* 分頁物件
* @author Administrator
*/
public class Page<T> {
/**
* 頁碼
*/
private int pageno;
/**
* 每頁顯示的記錄條數
*/
private int pagesize;
/**
* 資料集合(需要顯示在網頁中的資料)
*/
private List<T> dataList;
/**
* 總記錄條數
*/
private int totalsize;
public Page(String pageno) {
this.pageno = (pageno == null ? 1 : Integer.parseInt(pageno));
this.pagesize = Const.PAGE_SIZE;
this.dataList = new ArrayList<T>();
}
public int getPageno(){
return pageno;
}
public int getPagesize(){
return pagesize;
}
public List<T> getDataList(){
return dataList;
}
public void setTotalsize(int totalsize){
this.totalsize = totalsize;
}
public int getTotalsize(){
return totalsize;
}
public int getPagecount(){
return totalsize%pagesize == 0 ? totalsize/pagesize : totalsize/pagesize + 1;
}
/**
* 通過業務SQL語句獲取分頁SQL語句
* @param sql 業務SQL
* @return 分頁SQL語句
* 這是非常核心的,通過多次巢狀,嵌套出分頁sql語句的編寫
*/
public String getSql(String sql){
return "select t1.* from (select t.*,rownum as linenum from ("+sql+") t where rownum<=" + pageno*pagesize + ") t1 where t1.linenum>" + (pageno-1)*pagesize;
}
}
有了這個分頁物件,我就可以利用它了,看我們動態引數分頁查詢的過程,重點看註釋步驟:
/**
* 動態引數查詢,難度最大的是SQL語句動態拼接。(因為查詢提交內容不定,查詢提交個數不定)
* @author Administrator
*/
public class PageQueryInvServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//解決請求體的中文亂碼問題
//request.setCharacterEncoding("GB18030");
//建立分頁物件
Page<Investor> page = new Page<Investor>(request.getParameter("pageno"));
//獲取查詢提交的資料
String invregnum = request.getParameter("invregnum");
String invname = request.getParameter("invname");
String startdate = request.getParameter("startdate");
String enddate = request.getParameter("enddate");
//拼接業務SQL,注意其中的技巧,where 1=1,另外這裡使用StringBuilder提高拼接的效率
StringBuilder sql = new StringBuilder("select i.invregnum,i.invname,i.regdate,u.username,i.cty from t_invest i join t_user u on i.usercode=u.usercode where 1=1");
StringBuilder totalsizeSql = new StringBuilder("select count(*) as totalsize from t_invest i join t_user u on i.usercode=u.usercode where 1=1");
//建立list集合用來繫結下標和內容,利用的list下標和值對應關係的特點
List<String> paramList = new ArrayList<String>();
//動態引數拼接動態SQL語句
if(StringUtil.isNotEmpty(invregnum)){
sql.append(" and i.invregnum = ?");
totalsizeSql.append(" and i.invregnum = ?");
paramList.add(invregnum);
}
if(StringUtil.isNotEmpty(invname)){
sql.append(" and i.invname like ?");
totalsizeSql.append(" and i.invname like ?");
paramList.add("%" + invname + "%");
}
if(StringUtil.isNotEmpty(startdate)){
sql.append(" and i.regdate >= ?");
totalsizeSql.append(" and i.regdate >= ?");
paramList.add(startdate);
}
if(StringUtil.isNotEmpty(enddate)){
sql.append(" and i.regdate <= ?");
totalsizeSql.append(" and i.regdate <= ?");
paramList.add(enddate);
}
//呼叫獲取分頁SQL
String pageSql = page.getSql(sql.toString());
//連線資料庫查詢資料
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
try {
conn = DBUtil.getConnection();
ps = conn.prepareStatement(pageSql);
//給?賦值(重點),這裡list的巧妙使用
for(int i=0;i<paramList.size();i++){
ps.setString(i+1, paramList.get(i));
}
//執行查詢語句,返回查詢結果集
rs = ps.executeQuery();
//遍歷結果集,每遍歷一次,封裝Investor物件,將其新增到List集合中
while(rs.next()){
Investor inv = new Investor();
inv.setInvregnum(rs.getString("invregnum"));
inv.setInvname(rs.getString("invname"));
inv.setRegdate(rs.getString("regdate"));
inv.setUsername(rs.getString("username"));
inv.setCty(rs.getString("cty"));
page.getDataList().add(inv);
}
//查詢總記錄條數,並且設定到分頁物件中
ps = conn.prepareStatement(totalsizeSql.toString());
//給?賦值
for(int i=0;i<paramList.size();i++){
ps.setString(i+1, paramList.get(i));
}
rs = ps.executeQuery();
if(rs.next()){
page.setTotalsize(rs.getInt("totalsize"));
}
} catch (Exception e) {
e.printStackTrace();
} finally{
DBUtil.close(conn, ps, rs);
}
//將分頁物件儲存到request範圍中
request.setAttribute("pageObj", page);
//轉發
}
}
分頁查詢將資料量分成幾批顯示到頁面上。就像我們的書本,這不過這裡的動態,可能因為查詢條件的不同,頁面的內容就不同,所以靈活應用,弄清楚查詢條件,編寫好分頁查詢語句,那麼什麼問題都解決了。