You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MySQL保存/修改/删除触发器时导致整个程序冻结问题

问题成因

你遇到的MySQL冻结问题是触发器代码存在死循环导致的,具体问题点如下:

  • 游标循环无终止逻辑:当游标遍历完ps_ets_ept_alegenos表所有数据后,会触发NOT FOUND处理器将ch_done设为1,但你的代码没有在检测到ch_done=1时执行LEAVE语句跳出循环,后续的字符串匹配、拼接、变量重置逻辑会无限重复执行,持续消耗数据库连接资源,最终导致程序无响应。
  • 状态判断逻辑冗余错误:你在检测到ch_done=1时仅重复给ch_done赋值为1,没有做任何拦截处理,游标读到末尾后会反复触发无效fetch,永远走不到关闭游标、结束触发器的逻辑。
  • 额外性能隐患:该触发器绑定UPDATE操作后,每次更新任意产品都会全表扫描过敏原表做字符串匹配,还会往pruebaTablas表插入数据,更新频繁时很容易引发表锁、行锁等待,进一步加剧卡死问题。
修复后可正常运行的触发器代码
BEGIN
    declare contentCursor text;
    declare tableContent text default '<table width="250" cellpadding="0" cellspacing="0"><tbody>';
    declare alegenos varchar(30);
    declare contieneAlergenos int;
    declare trazasCerca int;
    declare siCerca text default "";
    DECLARE ch_done INT DEFAULT 0;

    DECLARE alegenosCursor cursor for select Nombre from ps_ets_ept_alegenos;
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET ch_done = 1;

    BLOCK2: begin
        open alegenosCursor;
        bucleAlergenos:LOOP 
            fetch alegenosCursor into alegenos;
            -- 读到游标末尾立刻跳出循环,避免死循环
            IF ch_done = 1 THEN 
                LEAVE bucleAlergenos;
            END IF;

            -- 匹配当前过敏原是否在旧内容中存在
            SELECT LOCATE(alegenos, old.content) into contieneAlergenos;
            if contieneAlergenos>0 then 
                -- 判断是痕量(Trazas)还是明确含有(Si)
                SELECT LOCATE("Trazas",SUBSTR(old.content,contieneAlergenos+length(alegenos)+44,7)) INTO trazasCerca;
                if trazasCerca>0 then 
                    SET siCerca="Trazas";
                else 
                    SET siCerca="Si";
                end if;
                -- 拼接含有/痕量的表格行
                SELECT CONCAT(tableContent,'<tr><td width="60%" align="left"><strong>', alegenos, '</strong></td><td width="40%" align="left"> ', siCerca, '</td></tr>') INTO tableContent;
            else 
                -- 拼接不含该过敏原的表格行
                SELECT CONCAT(tableContent,'<tr><td width="60%" align="left"><strong>', alegenos, '</strong></td><td width="40%" align="left">No</td></tr>') INTO tableContent ;
            end if;
                    
            -- 重置临时变量
            SET siCerca="";
            SET trazasCerca=0;  
            SET contieneAlergenos=0;
        END LOOP bucleAlergenos;

        -- 拼接表格闭合标签,写入测试表
        select CONCAT(tableContent,'</tbody></table>') INTO tableContent;
        insert into pruebaTablas VALUES (tableContent);
        set tableContent="";
        close alegenosCursor;
    END BLOCK2; 
END
更优实现思路
  • 不建议在数据库触发器中做HTML格式拼接:数据库的核心职责是存储、查询结构化数据,HTML渲染属于前端/业务层逻辑,放到业务代码中实现后续调整样式、修改规则不需要变更数据库逻辑,也不会给数据库增加额外的计算压力。
  • 避免用游标逐行处理字符串拼接:如果确实需要在数据库层生成拼接结果,可以用GROUP_CONCAT函数一次性聚合所有过敏原的匹配结果,不需要手动写游标循环,性能会有明显提升。
  • 替换字符串匹配的过敏原判断逻辑:不要用LOCATE做字符串模糊匹配判断产品是否含有过敏原,建议单独建产品-过敏原关联表,结构化存储每个产品对应过敏原的状态(无/含有/痕量),从根源上避免字符串匹配的误差,查询和维护效率更高。

内容的提问来源于stack exchange,提问作者Kimuy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 18:54:23