MySQL 异常处理

MySQL 异常处理

在存储过程或自定义函数中,若执行 SQL 语句时发生错误(如主键冲突、数据类型不匹配),默认会直接中断执行并抛出错误。通过异常处理,可捕获错误并执行自定义逻辑(如回滚事务、返回错误信息),保证程序的健壮性。

异常处理的核心语法(DECLARE HANDLER)

DELIMITER //
CREATE PROCEDURE 存储过程名(IN 参数 类型, OUT err_msg VARCHAR(255))
BEGIN
    -- 1. 声明异常处理:捕获指定错误,执行自定义逻辑
    -- 格式:DECLARE 处理器类型 HANDLER FOR 错误类型 SET 变量 = 值;
    -- 处理器类型:CONTINUE(继续执行)、EXIT(退出当前块)
    -- 错误类型:SQLSTATE '错误码'(如 '23000' 表示主键冲突)、SQLWARNING(所有警告)、NOT FOUND(无数据)、SQLEXCEPTION(所有异常)
    
    -- 示例1:捕获主键冲突(SQLSTATE '23000'),返回错误信息并继续执行
    DECLARE CONTINUE HANDLER FOR SQLSTATE '23000' 
    BEGIN
        SET err_msg = '错误:主键冲突,数据已存在';
    END;
    
    -- 示例2:捕获所有异常,回滚事务并退出
    DECLARE EXIT HANDLER FOR SQLEXCEPTION
    BEGIN
        ROLLBACK;  -- 回滚未提交的事务
        SET err_msg = '错误:执行失败,已回滚';
    END;
    
    -- 2. 业务逻辑(含事务)
    START TRANSACTION;
    INSERT INTO user (id, username) VALUES (参数, CONCAT('user_', 参数));  -- 可能触发主键冲突
    COMMIT;
    SET err_msg = '执行成功';
END //
DELIMITER ;

常见错误码与含义

SQLSTATE 错误码 对应错误类型 常见场景
'23000' 完整性约束冲突 主键重复、外键关联不存在、唯一索引冲突。
'1264' 数值超出范围 插入的数值超过字段定义的范围(如 TINYINT 字段插入 256)。
'1366' 数据类型不匹配 字符串插入数值字段、日期格式错误(如 '2024-13-01' 插入 DATE 字段)。
'02000' 无数据返回 SELECT ... INTO 变量时,查询结果为空(无匹配数据)。

示例:带异常处理的转账存储过程

-- 需求:转账过程中捕获“余额不足”“账户不存在”等错误,返回错误信息
DELIMITER //
CREATE PROCEDURE transfer(
    IN from_id INT,  -- 转出账户ID
    IN to_id INT,    -- 转入账户ID
    IN amount DECIMAL(10,2),  -- 转账金额
    OUT err_msg VARCHAR(255)  -- 输出错误信息
)
BEGIN
    DECLARE from_balance DECIMAL(10,2);  -- 转出账户余额
    DECLARE to_exists INT;  -- 转入账户是否存在(1=存在,0=不存在)
    
    -- 异常处理1:捕获所有异常,回滚事务
    DECLARE EXIT HANDLER FOR SQLEXCEPTION
    BEGIN
        ROLLBACK;
        SET err_msg = '转账失败:系统异常';
    END;
    
    -- 异常处理2:捕获“无数据”错误(如查询账户不存在)
    DECLARE CONTINUE HANDLER FOR NOT FOUND
    BEGIN
        SET err_msg = '转账失败:账户不存在';
    END;
    
    -- 1. 检查转入账户是否存在
    SELECT COUNT(*) INTO to_exists FROM account WHERE id = to_id;
    IF to_exists = 0 THEN
        SET err_msg = '转账失败:转入账户不存在';
        RETURN;  -- 退出存储过程
    END IF;
    
    -- 2. 查询转出账户余额
    SELECT balance INTO from_balance FROM account WHERE id = from_id;
    IF from_balance < amount THEN
        SET err_msg = '转账失败:余额不足';
        RETURN;
    END IF;
    
    -- 3. 执行转账(事务)
    START TRANSACTION;
    UPDATE account SET balance = balance - amount WHERE id = from_id;  -- 转出
    UPDATE account SET balance = balance + amount WHERE id = to_id;    -- 转入
    COMMIT;
    
    SET err_msg = '转账成功';
END //
DELIMITER ;

-- 调用转账存储过程(测试余额不足场景)
SET @err = '';
CALL transfer(1, 2, 1000, @err);  -- 假设账户1余额为500
SELECT @err;  -- 输出:转账失败:余额不足
posted @ 2025-10-29 16:05  Jing61  阅读(14)  评论(0)    收藏  举报