我有一个简单的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
现在,从上面更新的表继续,为了在事务中引入错误,我更改事务,使第二个更新语句的Id为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。
这是因为您的第二个实验实际上是成功的并执行了。当存在比较两种不同数据类型的操作时,SQL Server将执行隐式转换。有关更多详细信息,请参阅数据类型优先级。所以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
没有造成任何错误。它只是没有返回任何带有Id = '24'
的行,但没有错误。
您的第三个事务导致了一个错误,这就是回滚UPDATE
的原因。
update tblAccountBalance set Balance = Balance + 100 where Id = 'A24' --note the Id here is changed
以上将导致如下错误:
将varchar值"A24"转换为数据类型时转换失败内部
由于您的Id
是INT
,SQL Server尝试将A24
(即VARCHAR
)转换为INT
,但未能转换,因此出现错误。
您的第二个实验成功了,因为nvarchar
可以隐式转换为int
。字符串'24'
可以转换为24
的整数值。请参见隐式转换。