解決MySQL遊標循環多執行一次的問題 MySQL存儲過程使用遊標時,多執行一次的問題
一、問題描述
1、在寫MySQL存儲過程,使用到遊標遍歷數據時,遇到一個問題:遊標的循環比數據集填充到遊標要多執行1次。
2、表述不清,這樣理解:填充到遊標時,select 查詢到10條, 實際循環會執行 11次。 即永遠 n+1 多一次。
二、問題重現
1、如下,存儲過程 pro_multi() ,將會執行 2次。
DROP PROCEDURE IF EXISTS pro_multi ;
CREATE PROCEDURE pro_multi()
BEGIN
DECLARE count int DEFAULT 0 ; -- 定義 count 計數
DECLARE done int DEFAULT FALSE; -- 定義遊標循環變量
DECLARE my_cursor CURSOR FOR( SELECT 1) ; -- 定義遊標,獲取到1條數據
DECLARE CONTINUE HANDLER FOR NOT FOUND set done = TRUE ; -- 遊標循環結束時,將控制變量done = TRUE
OPEN my_cursor ; -- 打開遊標
WHILE NOT done DO -- 開始循環
FETCH my_cursor INTO count ; -- 獲取一行數據,賦值到自定義變量中
INSERT INTO `batch` (`id`,`name`, `age`) VALUES (UUID(),count, '0'); -- 插入數據
SET count = count + 1; -- 變量+1
END WHILE ; -- 結束循環
END ;
三、問題定位
1、原因:遊標第一次獲取數據時,正常 ;第二次獲取數據時,執行到末尾,沒有數據,此時done = TRUE , 然而下面的 INSERT 語句,卻不知道遊標已經到末尾,仍然插入了一條數據。
2、從而造成了,MySQL遊標循環執行多一次的問題。
四、問題解決
1、方法一:在循環體外,先獲取一次遊標數據
DROP PROCEDURE IF EXISTS pro_multi_fix1 ;
CREATE PROCEDURE pro_multi_fix1()
BEGIN
-- 解決 多執行一次的問題
DECLARE count int DEFAULT 0 ; -- 定義 count 計數
DECLARE done int DEFAULT FALSE; -- 定義遊標循環變量
DECLARE my_cursor CURSOR FOR( SELECT 1) ; -- 定義遊標,獲取到1條數據
DECLARE CONTINUE HANDLER FOR NOT FOUND set done = TRUE ; -- 遊標循環結束時,將控制變量done = TRUE
OPEN my_cursor ; -- 打開遊標
FETCH my_cursor INTO count ; -- 循環外,先獲取一次數據
WHILE NOT done DO -- 開始循環
INSERT INTO `batch` (`id`,`name`, `age`) VALUES (UUID(),count, '0'); -- 插入數據
FETCH my_cursor INTO count ; -- 再一次獲取數據
SET count = count + 1; -- 變量+1
END WHILE ; -- 結束循環
END ;
2、方法二:在循環體內,增加判斷遊標是否已經執行結束
DROP PROCEDURE IF EXISTS pro_multi_fix2 ;
CREATE PROCEDURE pro_multi_fix2()
BEGIN
-- 解決 多執行一次的問題 (方法二)
DECLARE count int DEFAULT 0 ; -- 定義 count 計數
DECLARE done int DEFAULT FALSE; -- 定義遊標循環變量
DECLARE my_cursor CURSOR FOR( SELECT 1) ; -- 定義遊標,獲取到1條數據
DECLARE CONTINUE HANDLER FOR NOT FOUND set done = TRUE ; -- 遊標循環結束時,將控制變量done = TRUE
OPEN my_cursor ; -- 打開遊標
WHILE NOT done DO -- 開始循環
FETCH my_cursor INTO count ; -- 再一次獲取數據
IF NOT done THEN -- 增加判斷,遊標循環結束後,不插入數據
INSERT INTO `batch` (`id`,`name`, `age`) VALUES (UUID(),count, '0'); -- 插入數據
END IF ;
SET count = count + 1; -- 變量+1
END WHILE ; -- 結束循環
END ;
---- 還有更多 ....
MyBatis調用存儲過程,MyBatis調用函數的使用方法
MySQL 創建函數, MySQL定義函數實現漢字轉拼音 MySQL漢字轉拼音MySQL漢字生成拼音字符串
MySQL WHILE和LOOP和REPEAT循環的用法區別 MySQL三種循環的區別 MySQL循環使用方法