mysql - 为什么设置无效的枚举值不会导致调用错误处理程序?
问题描述
我有两张桌子。Mysql 5.7,表有 Innodb 存储引擎。
create table test_tran (id integer, descr varchar(255));
create table test_enum (id int, flag enum('good','not good') not null);
一个有效的记录被插入到 test_enum 表中
insert into test_enum values(1,'good')
我已经定义了事务的存储过程,它试图更新枚举列中的无效值。它还捕获错误以回滚事务,然后重新发出错误信号。
SET sql_mode = 'STRICT_ALL_TABLES';
DROP PROCEDURE IF EXISTS test_tran;
DELIMITER $$
CREATE PROCEDURE test_tran
(
i_case integer
)
BEGIN
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
RESIGNAL;
END;
START TRANSACTION;
IF i_case=0 THEN
insert into test_tran values (1, 'abc');
update test_enum set flag='random';
ELSE
insert into test_tran values (3, 'else_1_abc');
insert into test_tran values (4, 'else_2_abc');
END IF;
COMMIT;
END $$
DELIMITER ;
我执行
call test_tran(0)
并得到一个错误 - “错误代码:1265。数据被截断列'标志'在行”
我期待下面的语句回滚
insert into test_tran values (1, 'abc');
但是,我看到它正在提交,并且我看到 test_tran 表中插入的行。是什么导致了这个问题?
解决方案
错误消息中缺少关键信息:SQLSTATE。完整的错误信息应该是:
错误:1265 (01000):第 1 行的列“标志”的数据被截断
(可能正在使用的客户端未在错误消息中包含 SQLSTATE;以上是 MySQL Shell 生成的内容。)
状态的文档DECLARE ... HANDLER
:
condition_value
DECLARE ... HANDLER
表示激活处理程序的特定条件或条件类别。它可以采取以下形式:...
- SQLWARNING:以 '01' 开头的 SQLSTATE 值类的简写。
...
- SQLEXCEPTION:不以“00”、“01”或“02”开头的 SQLSTATE 值类的简写。
通过设置无效枚举列生成的错误是 SQLWARNING 类的一部分,而不是 SQLEXCEPTION,因此永远不会调用错误处理程序,并且在过程退出后事务仍然处于活动状态,这就是插入的行出现在test_tran
. 请注意,此时可以手动回滚事务;此外,关闭会话将导致自动回滚。
要处理 中的错误test_tran
,只需将 SQLEXCEPTION 更改为 SQLWARNING,或者(可能更合适)向处理程序添加条件:
CREATE PROCEDURE test_tran (i_case integer)
BEGIN
DECLARE EXIT HANDLER FOR SQLWARNING, NOT FOUND, SQLEXCEPTION
BEGIN
ROLLBACK;
RESIGNAL;
END;
...
其他读者注意:有些人可能想知道为什么DECLARE ... HANDLER
需要它;为什么整个交易没有被错误取消。InnoDB 错误处理页面描述了 何时发生隐式回滚。整个事务自动回滚的唯一情况是存在事务死锁,或者在等待时锁超时并且服务器以--innodb-rollback-on-timeout
set 启动。将列设置为无效enum
值
[is] 主要被 MySQL 代码层(在 InnoDB 存储引擎级别之上)检测到,它们会回滚相应的 SQL 语句。锁不会在单个 SQL 语句的回滚中释放。
换句话说,设置无效枚举值的查询被回滚,但事务不是。
推荐阅读
- rest - Apache Camel 休息路线中的路径变量
- api - 我需要 Azure DevOps REST API 来为组本身以及存储库、管道和版本设置权限
- zoho - Zoho cretor + zoho 图书集成
- reactjs - 使用突变反应查询重置formik表单
- c - 如何在 C 中序列化数据以在套接字中发送
- spring - CXF - 在 SOAP ws 客户端请求的 http 标头中传递 oauth2 不记名令牌
- c#-4.0 - 使用 SSIS 中的脚本组件生成用于将电子邮件列转换为 15 位列的哈希码
- javascript - 如何在滑块 React.js 之外添加自定义按钮组
- python - 从数据框列中选择特定值
- php - 如何使用循环(在 php 中)在一页中显示多个 fetch 函数?