sqlserver 为什么事务失败没有回滚

初学数据库便知道,事务应该有原子性:要求事务要么全部完成,要么全部不完成,不能停滞在某个中间状态。然而,在下面的例子中事务却没有完全“回滚”,导致了异常数据的发生,为什么?

 

一、 问题复现

CREATE TABLE [dbo].[test1]([id] [int] NOT NULL,[testname] [varchar](10) NULL) ON [PRIMARY]

现在执行一个事务,事务中包含两个insert操作,其中第一个insert操作的testname字段超过了最大长度10

BEGIN TRANSACTION;
INSERT INTO [test1] VALUES (1,'123456789101');
INSERT INTO [test1] VALUES (888,'12345');
COMMIT TRANSACTION;

如预料的一样,SQL Server在执行第一条语句时报错

image

“按理”说来,这个事务执行会失败,第二条插入语句会回滚,但实际结果却是:

select * from [dbo].[test1];

image

在某些场景下,这会导致异常数据的发生。

 

二、 原因分析

根据MSDN,默认SQL Server并不会回滚事务,即使事务中的某个语句报错,事务还是会继续执行下去,除非非常严重的错误(serverity level is greater or equals 16)。

这是由数据库选项XACT_ABORT决定的,默认XACT_ABORT为OFF,

When SET XACT_ABORT is OFF, in some cases only the Transact-SQL statement that raised the error is rolled back and the transaction continues processing. Depending upon the severity of the error, the entire transaction may be rolled back even when SET XACT_ABORT is OFF. OFF is the default setting.

如果想规避这个问题,微软告诉我们设置XACT_ABORT为on,这样事务中任何一个语句报错都会回滚整个事务。

SET XACT_ABORT ON

当然,你也可以使用try、catch人工捕获错误以便回滚或者在程序中使用事务。

 

三、 为什么会有这么奇葩的设计呢?

SQL Server为什么默认不完全回滚呢?百思不得其解。求助MSDN时邹大侠给的一个解释虽然有道理(谢谢邹大侠),但还是觉得不够完美,因为即使是为了能够让开发人员自己来控制事务的状态,也不应该把XACT_ABORT默认设置为OFF,相反,如果设置为on倒是可以接受。

image

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值