1. 程式人生 > >mysql中用儲存過程做分頁操作

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);
	}
}