由於還在開發階段,每次測試完之後需要清理數據庫表,然後待清理的表數量較多,且有些基礎數據表需要保留,有些表(如用戶表)僅保留部分記錄,由於有個發郵件的定時器,還得保證清理數據的順序。所以嘗試使用存儲過程來實現一鍵清理數據的功能,僅以此過程分享給大家
思路:
- 首先是創建名爲clearMaterialDatabase的函數,暫時保留一個入參isKeepMaterial來控制是否保留材料信息。
- 通過MySQL中自帶的信息數據庫INFORMATION_SCHEMA可以獲取指定數據庫的基本信息,包括表名、權限和數據類型等。在通過
CONCAT()
函數拼接指定數據庫中各個表表名稱,比如CONCAT('DELETE FROM',' wz_input')
,結果就成了一個刪除語句DELETE FROM wz_input
,將這些語句組成一個結果集 - 通過遍歷這個結果集,執行指定的SQL語句,來達到批量刪除的目的。對於需要特殊處理的表,在用流程控制語句
IF ELSEIF
來處理,利用預處理API(EXECUTE stmt)執行相應的SQL語句
存儲過程源碼:
CREATE DEFINER=`root`@`localhost` PROCEDURE `clearMaterialDatabase`(IN `isKeepMaterial` VARCHAR(255))
BEGIN
#Routine body goes here...
#定義控制流程
DECLARE i INT;
#定義拼接的sql語句
DECLARE strClear VARCHAR(256);
DECLARE done INT DEFAULT 0;
#定義遊標
DECLARE curOne CURSOR FOR SELECT CONCAT('TRUNCATE TABLE ',TABLE_NAME,';') as ClearTable
FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'material_wz1702';
#綁定控制變量到遊標,遊標循環結束自動轉爲True
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
#打開遊標
OPEN curOne;
#進入循環
FETCH curOne INTO strClear;
repeat_label: REPEAT
FETCH curOne INTO strClear;
#SELECT strClear;
#開始控制流程IF-ELSEIF
#是否保留材料信息
IF (isKeepMaterial AND ((strClear LIKE '%tc_material;')OR(strClear LIKE '%tc_material_detail;')OR(strClear LIKE '%tc_material_subject;'))) THEN
ITERATE repeat_label;
#默認保留管理員賬號
ELSEIF(strClear LIKE '%sys_user;') THEN
SET @mysql = "DELETE from sys_user WHERE login_name not like 'admin'";
PREPARE stmt from @mysql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
ITERATE repeat_label;
#默認保留數據字典/默認保留菜單字典/默認保留主頁配置/默認保留角色信息/默認保留合同模板/最後清理郵件記錄,防止清理過程中重複發送
ELSEIF((strClear LIKE '%sys_dict;') OR (strClear LIKE '%sys_menu;') OR (strClear LIKE '%sys_config;')OR(strClear LIKE '%sys_role;')OR(strClear LIKE '%wz_contract_template')OR(strClear LIKE '%wz_bid_mail;')) THEN
ITERATE repeat_label;
#默認保留到項目層級
ELSEIF(strClear LIKE '%sys_office;') THEN
SET @mysql = "DELETE FROM sys_office WHERE id > ( SELECT id FROM ( SELECT id FROM sys_office WHERE NAME = '項目級' AND del_flag = 0 ) targetId )";
PREPARE stmt from @mysql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
ITERATE repeat_label;
#結束控制流程
END IF;
#動態執行SQL語句
SET @mysql = strClear;
PREPARE stmt from @mysql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
UNTIL done = 1 END REPEAT;
#關閉遊標
CLOSE curOne;
#最後清理郵件記錄
SET @mysql = "TRUNCATE TABLE wz_bid_mail;";
PREPARE stmt from @mysql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END
過程準備:
1.MySQL預處理語句使用示例:
例一:通過文本字符拼接一個預處理語句
#創建一個函數求(X^2+Y^2)的平方根:
#?表示與參數進行綁定,?不需要用引號引用,相當於在prepare的時候就把sql寫死
PREPARE stmt1 FROM 'SELECT SQRT(POW(?,2) + POW(?,2)) AS result';
SET @X = 3;
SET @Y = 4;
EXECUTE stmt1 USING @X @Y;
輸出:
result
5
例二:將文本語句當做一個變量
#創建一個函數求(X^2+Y^2)的平方根:
SET@sqlText = 'SELECT SQRT(POW(?,2)) + POW((?,2)) AS result ';
#將sqlText作爲一個包含語句文本的變量放入預備語句stmt2中,表明prepare之前可以用@param變量的形式注入sql語句
PREPARE stmt2 FROM @sqlText;
SET @X = 6;
SET @Y = 8;
EXECUTE stmt2 USING @X,@Y;
輸出:
result
10
注:
- 該文本必須展現一個單一的SQL語句,而不是多個語句
- ‘?'字符不應加引號,即使您想要把它們與字符串值結合在一起,也不要加引號。參數製作符只能被用於數據值應該出現的地方,不用於SQL關鍵詞和標識符等
- 參數值只能有用戶變量提供,USING子句必須準確地指明用戶變量。用戶變量的數目與語句中的參數製造符的數量一樣多。
- 以下SQL語句可以被用在預製語句中:CREATE TABLE, DELETE, DO, INSERT, REPLACE, SELECT, SET, UPDATE和多數的SHOW語句。目前不支持其它語句。
本章參考文檔:理解Mysql prepare預處理語句
2.基於Navicat 12.0創建MySQL存儲過程的例子:
- 首先進入函數嚮導:
Navicat 12.0功能區
->函數
->新建函數
->過程
如何需要設置存儲過程的參數,可以在這快速設置,如這裏傳入兩個入參X和Y,類型爲INT,出參R,類型爲INT,所以嚮導如圖所示:(注:這裏只是提供圖形化的參數設置,也可以跳過直接在存儲過程中添加)