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.
由于您的 Id
是 INT
,SQL 服务器尝试将 A24
(即 VARCHAR
转换为 INT
但失败了如此错误。
您的第二个实验成功了,因为 nvarchar
可以隐式转换为 int
。字符串 '24'
可以转换为 24
的整数值。参见 Implicit Conversions。
我有一个简单的 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.
由于您的 Id
是 INT
,SQL 服务器尝试将 A24
(即 VARCHAR
转换为 INT
但失败了如此错误。
您的第二个实验成功了,因为 nvarchar
可以隐式转换为 int
。字符串 '24'
可以转换为 24
的整数值。参见 Implicit Conversions。