mysql中用儲存過程做分頁操作
在資料庫中有一個很重要的查詢,叫分頁查詢,因為每每可能做查詢操作時符合查詢條件的資料太多,導致無法全部顯示在一個頁面上,不方便瀏覽,所以便想把資料一頁一頁的分別顯示,由此,便產生了分頁查詢這個操作。做一個對某個具體表的簡單的分頁查詢很簡單,只需在select語句的最後加上limit currentPage,PageSize即可,那麼,如何做對任意一個表的分頁查詢呢,今天,我便來和大家講一講如何做一個通用的分頁查詢工具,即可用任意的查詢條件,任意的排序列和排序型別來對任意表的任意的列進行查詢。
本文章分為兩部分:
1、儲存過程部分:在mysql資料庫中用儲存過程做分頁操作
2、jdbc中執行儲存過程:在java中用jdbc連線資料庫執行帶輸出引數的儲存過程
一、儲存過程部分
要用任意的查詢條件,任意的排序列和排序型別來對任意表的任意的列進行查詢,則輸入引數必須要有表名稱,要查詢的列名稱(或者列名稱的列表),查詢條件,排序列的名稱,排序的排序型別(降序desc或升序asc),另外,還需傳入需要顯示的當前頁的頁數和每頁的大小(即每頁需要顯示的資料條數),也可通過該查詢的儲存過程傳出查詢得到的資料總條數和總頁數。
CREATE procedure pro_page2( vtable_name varchar(20), #任意表 必填 vclumn_name varchar(30), #任意的查詢列 可選 vtiaojian varchar(50), #任意查詢條件 可選 sortcolumn varchar(20), #任意的排序列 可選 sorttype varchar(4), #任意的排序型別(asc,DESC) 可選 currentPage int, #當前頁碼 必填 recordNum int, #頁面大小 必填 out countPage int, #符合條件資料的總頁數 out countNum int) #符合條件的資料的總條數
寫好了儲存過程頭部的引數準備部分,就要正式做查詢了,不過,在查詢之前,先要對傳入的引數進行預處理,在輸入引數中表名稱,當前頁的頁數和每頁的大小為必須傳入的查詢引數,而要查詢的列名稱,查詢條件,排序列的名稱,排序的排序型別則為可選的輸入引數,即可傳入具體的值,也可為null值。
查詢列為空時,則預設為對所有的列進行查詢,即其值可為" * " ,查詢條件為空時,則預設為對所有的資料進行查詢,即其值可為恆成立的" 1=1 ",排序列為空時,則可預設為按主鍵即按每個表的id列進行排序,排序型別為空時,可預設為按降序排序。
BEGIN #設定查詢的起始位置 declare startNum int; #判斷是否填寫查詢列,查詢條件,排序列,排序型別 if vclumn_name is null or vclumn_name = '' THEN set vclumn_name='*'; end if; #判斷是否填寫查詢條件 if vtiaojian is null or vtiaojian='' then set vtiaojian = '1=1'; end if; #判斷是否填寫排序列,若未填寫則使用預設的排序列“_id”,需要事先約定好 if sortcolumn is null or sortcolumn = '' THEN set sortcolumn = '_id'; end if; #判斷是否填寫排序型別,若未給定或者不符合要求,則預設使用升序(ASC) if lower(sorttype) <> 'asc' and lower(sorttype) <> 'desc' then set sorttype = 'asc'; end if;
要把這些引數都用到select 語句中,不能直接將查詢語句寫成select clumn_name from tablb_name where limit ,這樣的話,字串" tablb_name "會被當做是一個表的表名,字串"clumn_name"會被當做是tablb_name這個表中的某一個列的列名,其餘的引數也是如此,不是將引數傳入select語句中,而是取其字面的意思。所以,要將引數傳入select語句中,需用concat()函式對select語句進行連線,然後對sql語句進行預編譯,再執行其預處理物件。
set startNum=(currentPage-1)*recordNum;
set @sql=concat("select ",vclumn_name," from ",vtable_name,
" where ",vtiaojian," order by ",sortcolumn," ",sorttype,
" limit ",startNum,",",recordNum);
#對sql語句進行預編譯
prepare stmt from @sql;
execute stmt;
deallocate prepare stmt;
對於輸出引數的獲取要用一個臨時變數將其值儲存起來,再將該臨時變數的值賦給輸出引數。
set @sql2=concat("select count(*) into @temptotalnum from ",vtable_name," where ",vtiaojian);
prepare stmt2 from @sql2;
execute stmt2;
set countNum = @temptotalnum;#將臨時變數中的資料賦值給輸出引數
deallocate prepare stmt2;
SET countPage=CEILING(countNum/recordNum);
end;
二、在jdbc中執行儲存過程
鑑於要執行的儲存過程中的輸入輸出引數較多,所以,為資料獲取和儲存的方便起見,新建了一個工具類來儲存各引數中的資料,命名為PageUtils
public class PageUtils {
private int currentPage;
private int pagesize;
private String tableName;
private String selections;
private String condition;
private String sortColumn;
private String sortType;
private int totalNum;
private int totalPage;
//儲存當前頁的資料
private List<Object[]> datas;
public int getCurrentPage() {
return currentPage;
}
public void setCurrentPage(int currentPage) {
this.currentPage = currentPage;
}
public int getPagesize() {
return pagesize;
}
public void setPagesize(int pagesize) {
this.pagesize = pagesize;
}
public String getTableName() {
return tableName;
}
public void setTableName(String tableName) {
this.tableName = tableName;
}
public String getSelections() {
return selections;
}
public void setSelections(String selections) {
this.selections = selections;
}
public String getCondition() {
return condition;
}
public void setCondition(String condition) {
this.condition = condition;
}
public String getSortColumn() {
return sortColumn;
}
public void setSortColumn(String sortColumn) {
this.sortColumn = sortColumn;
}
public String getSortType() {
return sortType;
}
public void setSortType(String sortType) {
this.sortType = sortType;
}
public int getTotalNum() {
return totalNum;
}
public void setTotalNum(int totalNum) {
this.totalNum = totalNum;
}
public int getTotalPage() {
return totalPage;
}
public void setTotalPage(int totalPage) {
this.totalPage = totalPage;
}
public List<Object[]> getDatas() {
return datas;
}
public void setDatas(List<Object[]> datas) {
this.datas = datas;
}
}
另建一個執行類來用jdbc連線資料庫執行儲存過程,並將所得的查詢結果和輸出引數全部儲存到PageUtils物件中,然後通過操作物件PageUtils中的list集合即可檢視所得資料(這裡主要要注意在執行儲存過程中對輸出引數的處理)。
public class ProcedureDemo{
public PageUtils procPaging(PageUtils pu) throws SQLException{
//獲取資料庫連線物件
Class.forName("com.mysql.jdbc.Driver");
//獲取預處理命令
Connection conn=DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306//mydb?username=root&password=123456");
CallableStatement cs=conn.prepareCall("{call pro_page2 (?,?,?,?,?,?,?,?,?)}");
cs.setInt(1, pu.getCurrentPage());
cs.setInt(2, pu.getPagesize());
cs.setString(3, pu.getTableName());
cs.setString(4,pu.getSelections());
cs.setString(5,pu.getCondition());
cs.setString(6, pu.getSortColumn());
cs.setString(7,pu.getSortType());
//註冊輸出引數
cs.registerOutParameter(8, java.sql.Types.INTEGER);
cs.registerOutParameter(9, java.sql.Types.INTEGER);
//執行儲存過程
cs.execute();
//獲取指定位置的輸出引數集
int totalNum=cs.getInt(8);
int totalPage=cs.getInt(9);
pu.setTotalNum(totalNum);
pu.setTotalPage(totalPage);
//儲存查詢所得的結果集
List<Object[]> list=new ArrayList<>();
//獲取查詢的結果集
ResultSet rs =cs.getResultSet();
ResultSetMetaData rsmd = rs.getMetaData();
// 獲取資料的總列數
int count = rsmd.getColumnCount();
while (rs.next()) {
Object[] objs = new Object[count];
for (int i = 1; i <= count; i++) {
String label = rsmd.getColumnLabel(i);
// 獲取一列資料
Object obj = rs.getObject(label);
objs[i - 1] = obj;
}
list.add(objs);
}
pu.setDatas(list);
return pu;
}
public static void main(String[] args) {
PageUtils pu=new PageUtils();
pu.setCurrentPage=1;
pu.setPageSize=10;
pu.setTableName="employee";
procPaging(pu);
}
}