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; -- 输出:转账失败:余额不足

浙公网安备 33010602011771号