在數據庫中有一個很重要的查詢,叫分頁查詢,因爲每每可能做查詢操作時符合查詢條件的數據太多,導致無法全部顯示在一個頁面上,不方便瀏覽,所以便想把數據一頁一頁的分別顯示,由此,便產生了分頁查詢這個操作。做一個對某個具體表的簡單的分頁查詢很簡單,只需在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);
}
}