令人郁闷的“事务中的变量赋值错误”
2008-12-28 02:56
309 查看
事务中的变量(包括表变量)的操作是不受事务控制的。但是反过来,事务中的变量操作失败,却会导致事务提交失败,这个有点让人郁闷。
下面的脚本演示这个问题。示例演示分拆以逗号分隔的 @ids 中的每个 id, 如果这个 id 是数字(int型),则做后面的处理;如果不是数字(赋值失败,进入CATCH块),则跳过这个id,处理下一个。整个处理在一个事务中进行。
DECLARE
@ids varchar(1000);
SET @ids = '1,a,3,';
BEGIN TRY
BEGIN TRAN;
-- 循环分拆@ids 中以逗号分隔的每个id
WHILE CHARINDEX(',', @ids) > 0
BEGIN
DECLARE
@id int;
BEGIN TRY
-- 获取当前的id
SET @id =LEFT(@ids, CHARINDEX(',', @ids) - 1);
END TRY
BEGIN CATCH
-- 从@ids 中去掉当前的id
SET @ids = STUFF(@ids, 1, CHARINDEX(',', @ids), '');
CONTINUE;
END CATCH
-- 从@ids 中去掉当前的id
SET @ids = STUFF(@ids, 1, CHARINDEX(',', @ids), '');
-- 处理id
RAISERROR('current id: %d', 10, 1, @id) WITH NOWAIT;
END
COMMIT TRAN;
END TRY
BEGIN CATCH
IF XACT_STATE() <> 0
ROLLBACK TRAN;
SELECT
err_line = ERROR_LINE(),
err_message = ERROR_MESSAGE();
END CATCH
这个脚本执行后,输出消息如下:
current id: 1
current id: 3
err_line err_message
----------- -------------------------------------------------------
30 当前事务无法提交,而且无法支持写入日志文件的操作。请回滚该事务。
(1 行受影响)
这个结果表明,@ids 中的所有 id 确实在循环中处理过,但第二个id由于不是数字,所以跳过了。但最终提交事务失败了,因为第二个id不是数字,导致赋值失败,从而导致事务不可提交。
发现这个问题是因为公司在用Service Broker传递业务数据,由于传递的xml数据有问题,导致类型不是期望有类型,从而使处理失败。
个人觉得这个问题有点令人讨厌,按照我的理解,既然不受事务控制,那么它也不应该反过来影响事务,可是结果与理解的不一样,值得注意。
最后补充一下:写这个的重点在于提醒大家,在事务处理中,不要忽略那些看起来与事务无关的处理,它们出错一样会影响事务的最终提交。当然,解决的办法是把这与事务无关的操作放在事务外(不过如果是存储过程嵌套,就不好控制)。另外一个,只要处理可能会在事务中,则出错时都抛出错误,而不试图忽略错误,这样可以解决问题。
下面的脚本演示这个问题。示例演示分拆以逗号分隔的 @ids 中的每个 id, 如果这个 id 是数字(int型),则做后面的处理;如果不是数字(赋值失败,进入CATCH块),则跳过这个id,处理下一个。整个处理在一个事务中进行。
DECLARE
@ids varchar(1000);
SET @ids = '1,a,3,';
BEGIN TRY
BEGIN TRAN;
-- 循环分拆@ids 中以逗号分隔的每个id
WHILE CHARINDEX(',', @ids) > 0
BEGIN
DECLARE
@id int;
BEGIN TRY
-- 获取当前的id
SET @id =LEFT(@ids, CHARINDEX(',', @ids) - 1);
END TRY
BEGIN CATCH
-- 从@ids 中去掉当前的id
SET @ids = STUFF(@ids, 1, CHARINDEX(',', @ids), '');
CONTINUE;
END CATCH
-- 从@ids 中去掉当前的id
SET @ids = STUFF(@ids, 1, CHARINDEX(',', @ids), '');
-- 处理id
RAISERROR('current id: %d', 10, 1, @id) WITH NOWAIT;
END
COMMIT TRAN;
END TRY
BEGIN CATCH
IF XACT_STATE() <> 0
ROLLBACK TRAN;
SELECT
err_line = ERROR_LINE(),
err_message = ERROR_MESSAGE();
END CATCH
这个脚本执行后,输出消息如下:
current id: 1
current id: 3
err_line err_message
----------- -------------------------------------------------------
30 当前事务无法提交,而且无法支持写入日志文件的操作。请回滚该事务。
(1 行受影响)
这个结果表明,@ids 中的所有 id 确实在循环中处理过,但第二个id由于不是数字,所以跳过了。但最终提交事务失败了,因为第二个id不是数字,导致赋值失败,从而导致事务不可提交。
发现这个问题是因为公司在用Service Broker传递业务数据,由于传递的xml数据有问题,导致类型不是期望有类型,从而使处理失败。
个人觉得这个问题有点令人讨厌,按照我的理解,既然不受事务控制,那么它也不应该反过来影响事务,可是结果与理解的不一样,值得注意。
最后补充一下:写这个的重点在于提醒大家,在事务处理中,不要忽略那些看起来与事务无关的处理,它们出错一样会影响事务的最终提交。当然,解决的办法是把这与事务无关的操作放在事务外(不过如果是存储过程嵌套,就不好控制)。另外一个,只要处理可能会在事务中,则出错时都抛出错误,而不试图忽略错误,这样可以解决问题。
相关文章推荐
- sql:存储过程,事务,out参数 ,可以记录错误信息,系统变量的集合
- 分析 JavaScript 中令人困惑的变量赋值[转]
- 关于在mysql触发器中变量(prefixed with @)赋值错误的问题
- 无解 javascript 变量赋值 错误
- 探析 JavaScript 中令人困惑的变量赋值(转自快乐笛子的博客)
- 创建触发器时出现 PLS-00049: 错误的赋值变量 ':NEW.modify_man'
- 使用bool 类型变量赋值时的一个错误
- # include <errno.h >查看错误代码errno是调试程序的一个重要方法。当Linux C API函数发生异常时,一般会将errno变量赋值一个整数,不同的值表示不同的含义,可以通过查看
- 为什么为 const 变量重新赋值不是个静态错误
- 探析 JavaScript 中令人困惑的变量赋值
- keil(MDK)中出现error: #513: a value of type "int" cannot be assigned to an entity of type "char *",即函数返回值无法赋值给对应变量的错误
- 关于结构体对其方式错误引起的变量赋值错误
- Symbian中令人郁闷的错误【KESockDefaultMessageSlots|KErrServerBusy】
- Python捕捉命令输出、错误输出及赋值命令到变量的方法
- SQL不是同一类型的变量赋值最好转换成统一类型,否则引起莫名错误
- 分析 JavaScript 中令人困惑的变量赋值
- 分析 JavaScript 中令人困惑的变量赋值
- 创建触发器时出现 PLS-00049: 错误的赋值变量 ':NEW.land_name'
- C C++全局变量初始化 initializer element is not constant 错误 c++中为什么不能对全局变量在函数外赋值
- mysql存储过程定义一个判断事务是否异常的错误变量