我来自oracle背景,我对SQL Server感到困惑。
我想在insert命令中阻止SQL Server自动提交。所以我使用的是begin transaction
。在下面的演示中,我将100行插入测试表中,并且我将在事务结束时回滚。我期待的结果是90行(提交应该是30,60和90行),其余10条记录应该回滚。
CREATE TABLE test (TEST_ID INT);
GO
DECLARE @cnt INT=0;
BEGIN TRANSACTION t1;
WHILE @cnt < 100
BEGIN
INSERT INTO test values (@cnt);
SET @cnt += 1;
if (@cnt %30 = 0)
print 'commit '+cast(@cnt as varchar(100))
COMMIT TRANSACTION t1;
END
rollback transaction t1;
GO
首先,我确保关闭了SQL Server Management Studio自动提交,因为我遵循以下步骤:
Tools > Option > Query Execution > Sql Server > Ansi > checked the SET IMPLICIT_TRANSACTION
之后我运行了脚本,但是我得到了错误的结果,并且出现了一些错误。
ROLLBACK TRANSACTION请求没有相应的BEGIN TRANSACTION。
,行数为100!
我试图关闭我的连接并在oracle中再次打开它,当我插入时说100行而不提交最后说10行,其他人可以看到90行,但是我看到了100行,因为它是已保存在我的会话中。但看起来SQL Server在会话和事务方面的行为方式不同。
我遇到的另一个问题是关于while循环内部的提交,看起来它无法访问循环中的begin事务。当我运行命令时,我没有选择任何东西。只需按f5。即使我尝试了选择命令并运行但仍然给了我错误:
COMMIT TRANSACTION请求没有相应的BEGIN TRANSACTION。
我对SQL Server感到疯狂,我可以使用mysql和oracle轻松工作,但SQL Server ....
答案 0 :(得分:4)
实际上Sql Server不支持嵌套事务。它将允许您开始嵌套事务,但不允许在此处和那里回滚。实现此目的的唯一方法是使用save transaction语句。您可以在循环中向事务添加一些保存点,然后在外部循环中您可以回滚到该保存点并提交事务。这是一个例子:
DECLARE @cnt INT=0
Begin transaction
WHILE @cnt<100
BEGIN
INSERT INTO test values (@cnt)
SET @cnt+=1
if (@cnt%30=0)
begin
save transaction t1
end
END;
rollback transaction t1;
commit;
Select * from test
输出为0到89。
答案 1 :(得分:0)
分号没有你期望的效果。尝试更改此部分:
if (@cnt%30=0)
BEGIN
print 'commit '+cast(@cnt as varchar(100))
COMMIT TRANSACTION t1
END --IF @cnt
END --WHILE @cnt
答案 2 :(得分:0)
您的代码在WHILE
循环之外启动单个事务,尝试提交100次然后尝试回滚。 100你说?您的IF
语句没有BEGIN
/ END
来控制复合语句。 PRINT
将被执行三次,但COMMIT
将执行100次。
单个事务不能多次提交(或回滚),因此错误。您可以提交一个事务,然后在IF
内启动另一个事务,但这会将回滚限制为仅插入的最后一行。通常,您将启动事务,执行所有插入,然后提交或回滚。
除此之外:SQL Server中的嵌套事务没有按照您的想法执行。有关详细信息,请参阅here。