10.4.20-MariaDB存储过程游标嵌套循环死循环无输出问题求解
存储过程死循环问题排查及修复方案
核心问题原因
- 比较逻辑完全错误:需求要求是当前计算结果小于上一次的计算结果就停止,你的代码里全程和初始
min_vol值对比。以第一条测试数据为例,递减过程中计算结果从350开始持续上升到404+,始终大于初始的350,永远触发不到跳出条件,@mp会无限递减导致死循环。 - 无异常场景兜底逻辑:测试数据第三条的
a_val=0.5为正,二次函数开口向上,递减min_price的过程中函数值会持续升高,永远不会出现当前值小于上一次值的情况,没有兜底跳出机制必然死循环。 - 无递减下限保护:即使逻辑正确,异常场景下
@mp会一直降到负数甚至无限低,也会触发死循环。 - 会话级变量风险:代码中使用
@开头的会话变量,容易被会话上下文数据污染,建议使用存储过程局部变量。
前置操作
先确认阈值存储表py_range存在,不存在先执行创建:
CREATE TABLE IF NOT EXISTS py_range ( ean_id INT NOT NULL, threshold_price INT NOT NULL, PRIMARY KEY(ean_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
修复后的存储过程代码
DELIMITER // CREATE OR REPLACE PROCEDURE p1() BEGIN DECLARE done INT DEFAULT FALSE; DECLARE sk INT; DECLARE min_price, a, b, c, curr_mp, prev_vol, curr_vol FLOAT; DECLARE cur CURSOR FOR SELECT ean_id, min_price, a_val, b_val, c_val FROM py_price; DECLARE CONTINUE HANDLER FOR NOT FOUND SET done=TRUE; OPEN cur; read_loop: LOOP FETCH cur INTO sk, min_price, a, b, c; IF done THEN LEAVE read_loop; END IF; -- 初始化参数 SET curr_mp = min_price; -- 先算初始价格对应的vol作为上一次结果 SET prev_vol = a * curr_mp * curr_mp + b * curr_mp + c; in_loop: LOOP -- 兜底防止死循环:价格降到0直接跳出 IF curr_mp <= 0 THEN INSERT INTO py_range VALUES(sk, 0); LEAVE in_loop; END IF; -- 价格减1算当前值 SET curr_mp = curr_mp - 1; SET curr_vol = a * curr_mp * curr_mp + b * curr_mp + c; -- 当前值小于上一次值,说明找到临界点,临界点是curr_mp+1 IF curr_vol < prev_vol THEN INSERT INTO py_range VALUES(sk, curr_mp + 1); LEAVE in_loop; END IF; -- 更新上一次结果为当前值,继续循环 SET prev_vol = curr_vol; END LOOP in_loop; END LOOP read_loop; CLOSE cur; END // DELIMITER ;
验证结果
执行存储过程后查询py_range表,第一条数据ean_id=1的阈值为7,完全符合预期,第二条数据可正常计算出阈值,第三条数据触发兜底逻辑不会死循环。
内容的提问来源于stack exchange,提问作者Santosh
相关产品推荐
相关产品推荐

