一、定义条件 (DECLARE CONDITION)

语法:

DECLARE condition_name CONDITION FOR condition_value;
 
condition_value: {
    SQLSTATE [VALUE] 'sqlstate_value'
  | mysql_error_code
}

示例:

 方法一:使用 SQLSTATE 值(5字符字符串)

DECLARE table_not_found CONDITION FOR SQLSTATE '42S02';

 

 方法二:使用 MySQL 错误代码(数值)

DECLARE duplicate_key CONDITION FOR 1062;

DECLARE table_not_found CONDITION FOR 1146;

 

二、定义处理程序 (DECLARE HANDLER)

处理程序定义了当特定错误发生时应该执行什么操作。

语法:

DECLARE handler_type HANDLER FOR condition_value [, condition_value] ... statement;

handler_type: {

    CONTINUE   继续执行

   EXIT       退出当前BEGIN...END块

   UNDO       (MySQL不支持)

}

condition_value: {

    SQLSTATE [VALUE] 'sqlstate_value'

   condition_name

   SQLWARNING

   NOT FOUND

   SQLEXCEPTION

   mysql_error_code

}

处理程序类型 (handler_type):

 `CONTINUE`: 遇到错误后继续执行后续语句

 `EXIT`: 遇到错误后立即退出当前 `BEGIN...END` 块

 `UNDO`: 撤回操作(MySQL 目前不支持)

错误条件类型 (condition_value):

 `SQLSTATE 'xxxxx'`: 特定的5字符SQL状态值

 `condition_name`: 已定义的条件名称

 `SQLWARNING`: 所有以 '01' 开头的 SQLSTATE 值(警告)

 `NOT FOUND`: 所有以 '02' 开头的 SQLSTATE 值(未找到数据)

 `SQLEXCEPTION`: 所有不以 '01' 或 '02' 开头的 SQLSTATE 值(真正的异常)

 `mysql_error_code`: 特定的MySQL数值错误代码

 

三、处理程序示例

多种定义方式:

 1. 捕获特定 SQLSTATE

DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET @info = 'DUPLICATE KEY';

 2. 捕获特定错误代码

DECLARE EXIT HANDLER FOR 1062 SET @info = 'DUPLICATE ENTRY';

3. 使用预定义的条件(推荐,可读性高)

DECLARE duplicate_key_error CONDITION FOR 1062;

DECLARE EXIT HANDLER FOR duplicate_key_error

BEGIN

    SET @info = '重复键错误发生';

    SET @error_time = NOW();

END;

 

 4. 捕获某一类错误

DECLARE EXIT HANDLER FOR NOT FOUND SET @info = '未找到数据';

DECLARE EXIT HANDLER FOR SQLEXCEPTION SET @info = '发生异常';

 

四、完整示例分析

CREATE TABLE t8(s1 INT, PRIMARY KEY(s1));

DELIMITER //

CREATE PROCEDURE handlerdemo()

BEGIN

     定义处理程序:遇到主键冲突(23000)时继续执行,并设置变量

    DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' SET @X2 = 1;

    SET @X = 1;                      @X = 1

    INSERT INTO t8 VALUES(1);        成功插入

    SET @X = 2;                      @X = 2

    INSERT INTO t8 VALUES(1);        主键冲突,触发处理程序

    SET @X = 3;                      继续执行,@X = 3

END //

DELIMITER ;

 

CALL handlerdemo();

SELECT @X;   结果为 3

 

执行过程分析:

1. 第一次 INSERT 成功

2. 第二次 INSERT 因主键冲突失败,SQLSTATE = '23000'

3. 触发 CONTINUE HANDLER,执行 `SET @X2 = 1`

4. 继续执行后续的 `SET @X = 3`

5. 最终 @X 的值为 3

 

五、实际应用场景

场景1:优雅处理重复插入

DELIMITER //

CREATE PROCEDURE insert_user(

    IN p_username VARCHAR(50),

    IN p_email VARCHAR(100)

)

BEGIN

    DECLARE EXIT HANDLER FOR 1062 -- 重复键错误

    BEGIN

        SELECT '用户已存在,插入失败' AS result;

    END;

   

    INSERT INTO users(username, email) VALUES(p_username, p_email);

    SELECT '用户插入成功' AS result;

END //

DELIMITER ;

 

场景2:处理查询无结果的情况

DELIMITER //

CREATE PROCEDURE get_user_score(IN p_user_id INT)

BEGIN

    DECLARE v_score INT;

    DECLARE EXIT HANDLER FOR NOT FOUND

    BEGIN

        SELECT '用户不存在' AS result;

    END;

    SELECT score INTO v_score FROM users WHERE id = p_user_id;

    SELECT CONCAT('用户分数: ', v_score) AS result;

END //

DELIMITER ;

 

场景3:复杂的错误日志记录

DELIMITER //

CREATE PROCEDURE safe_operation()

BEGIN

    DECLARE EXIT HANDLER FOR SQLEXCEPTION

    BEGIN

         获取错误信息

        GET DIAGNOSTICS CONDITION 1

            @err_no = MYSQL_ERRNO,

            @err_msg = MESSAGE_TEXT;

         记录错误日志

        INSERT INTO error_logs(error_code, error_message, error_time)

        VALUES(@err_no, @err_msg, NOW());

          返回友好提示

        SELECT '操作失败,请联系管理员' AS result;

    END;

     主要业务逻辑

END //

DELIMITER ;

 

 六、最佳实践建议

1.  使用命名条件:提高代码可读性和可维护性

2.  合理选择处理类型:

     使用 `CONTINUE` 处理可恢复的错误

     使用 `EXIT` 处理严重错误

3.  分层处理:可以在嵌套的 `BEGIN...END` 块中定义不同的处理程序

4.  错误信息获取:使用 `GET DIAGNOSTICS` 获取详细的错误信息

5.  资源清理:在 `EXIT HANDLER` 中进行必要的资源释放和状态清理

七、获取错误信息

MySQL 5.6+ 支持更详细的错误信息获取:

DECLARE EXIT HANDLER FOR SQLEXCEPTION

BEGIN

    GET DIAGNOSTICS CONDITION 1

        @p1 = MYSQL_ERRNO,

        @p2 = MESSAGE_TEXT,

        @p3 = RETURNED_SQLSTATE;

     记录或处理错误信息

    INSERT INTO error_logs(...) VALUES(@p1, @p2, @p3, NOW());

END;

点赞(0)

C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:

一点编程也不会写的:零基础C语言学练课程

解决困扰你多年的C语言疑难杂症特性的C语言进阶课程

从零到写出一个爬虫的Python编程课程

只会语法写不出代码?手把手带你写100个编程真题的编程百练课程

信息学奥赛或C++选手的 必学C++课程

蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程

手把手讲解近五年真题的蓝桥杯辅导课程

Dotcpp在线编译      (登录可减少运行等待时间)