SQL 服务器事务成功但 ID 错误

SQL Server Transaction successful with wrong Id

我有一个简单的 SQL 语句来创建这样的 table:

Create table tblAccountBalance
(
    Id int,
    AccountName nvarchar(200),
    Balance int
)

insert into tblAccountBalance values (1, 'Mark', 1000);
insert into tblAccountBalance values (2, 'Mary', 1000);

导致

Id AccountName Balance
-----------------------
1  Mark        1000
2  Mary        1000

然后我创建一个这样的交易:

begin try
    begin transaction   -- must have transaction keyword here!
        update tblAccountBalance 
        set Balance = Balance - 100 
        where Id = 1

        update tblAccountBalance 
        set Balance = Balance + 100 
        where Id = 2

        commit transaction --or simply commit, but by default, it is commit WORK - thus you cannot specify transaction name, best is to put transaction
        print 'Transaction successful!'
end try
begin catch
    rollback transaction --or simply rollback, but again, it might be similar to transaction, best is to put transaction keyword
    print 'Transaction is rolled back!'
end catch

执行时,只需将 100 个单位的钱从 Mark 转移给 Mary:

Id AccountName Balance
-----------------------
1  Mark        900
2  Mary        1100

现在,从上面继续 - 更新 - table,为了在事务中引入错误,我更改事务以使第二个更新语句具有 nvarchar 作为 Id,如下所示:

begin try
    begin transaction
        update tblAccountBalance 
        set Balance = Balance - 100 
        where Id = 1

        update tblAccountBalance 
        set Balance = Balance + 100 
        where Id = '24'    -- note the Id here is changed

        commit transaction
        print 'Transaction successful!'
end try
begin catch
    rollback transaction
    print 'Transaction is rolled back!'
end catch

令我惊讶的是,执行上述查询会导致:

(1 row(s) affected)
(0 row(s) affected)
Transaction successful!

Id  AccountName Balance
-----------------------
1   Mark        800
2   Mary        1100

这不是想要的结果。

但是,如果我进一步从上面不需要的更新 table 结果继续修改事务(同样,在第二个更新 ID 中),如下所示:

begin try
    begin transaction
        update tblAccountBalance 
        set Balance = Balance - 100 
        where Id = 1

        update tblAccountBalance 
        set Balance = Balance + 100 
        where Id = 'A24'     -- note the Id here is changed

        commit transaction
        print 'Transaction successful!'
end try
begin catch
    rollback transaction
    print 'Transaction is rolled back!'
end catch

这导致:

(1 row(s) affected)
(0 row(s) affected)
Transaction is rolled back!

Id  AccountName Balance
------------------------
1   Mark        800
2   Mary        1100

这是我想要的结果。第二笔交易有什么问题?为什么更新仍然被执行?

如果重要的话,我正在使用 SQL Server 2014。

因为你的第二个实验确实成功并执行了。当有一个比较2种不同数据类型的操作时,SQL服务器将执行隐式conversion.Refer到Data Type Precedence以获得更多细节。所以你的 id = '24' 转换为 int 类型,所以它最终变成 id = 24。所以实验会扣除Mark的余额,加上id = 24记录的余额,但是因为没有这个id的记录,所以没有任何变化。

在你的第三个实验中,隐式转换失败(无法将 A24 转换为整数类型),最终事务被回滚。

您的第二笔交易成功,这就是 UPDATE 仍被执行的原因。您更改的 UPDATE 语句:

update tblAccountBalance set Balance = Balance + 100 where Id = '24' --note the Id here is changed

没有造成任何错误。它根本没有 return 任何带有 Id = '24' 的行,但没有错误。

您的第三次交易导致错误,这就是 UPDATE 被回滚的原因。

update tblAccountBalance set Balance = Balance + 100 where Id = 'A24' --note the Id here is changed

以上将导致如下错误:

Conversion failed when converting the varchar value 'A24' to data type int.

由于您的 IdINT,SQL 服务器尝试将 A24(即 VARCHAR 转换为 INT 但失败了如此错误。

您的第二个实验成功了,因为 nvarchar 可以隐式转换为 int。字符串 '24' 可以转换为 24 的整数值。参见 Implicit Conversions