SQL Server事务成功,ID错误

时间:2016-03-28 03:00:42

标签: sql sql-server transactions sql-server-2014

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

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单位转账给玛丽:

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

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

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

这不是理想的结果。

但是,如果我继续使用修改后的事务(再次,在第二个更新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.

3 个答案:

答案 0 :(得分:3)

这是因为你的第二个实验实际上已成功并被执行。当存在比较2种不同数据类型的操作时,SQL Server将执行隐式转换。有关详细信息,请参阅Data Type Precedence。因此,您的id = '24'转换为int类型,因此最终会变为id = 24。因此,实验将从Mark中扣除余额,并使用id = 24添加记录余额,但由于没有此ID的记录,因此没有任何变化。

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

答案 1 :(得分:1)

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

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

没有造成任何错误。它只是没有返回Id = '24'的任何行,但没有错误。

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

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

以上将导致如下错误:

  

将varchar值'A24'转换为数据类型时转换失败   中间体

由于您的IdINT,SQL Server会尝试将A24 VARCHAR转换为INT,但无法执行此操作,从而导致错误。

答案 2 :(得分:1)

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