T-SQL无法回滚
我有一些代码,它有一个纯粹的顺序流,没有事务。 我用begin事务和commit事务将它们夹在一起T-SQL无法回滚,sql,tsql,sql-server-2008,Sql,Tsql,Sql Server 2008,我有一些代码,它有一个纯粹的顺序流,没有事务。 我用begin事务和commit事务将它们夹在一起 begin transaction ......--My code here...... ...... ......--code to create Table1 ...... ALTER TABLE [dbo].[Table1] WITH CHECK ADD CONSTRAINT [FK_constraint] FOREIGN KEY([field1], [field2]) REFEREN
begin transaction
......--My code here......
......
......--code to create Table1
......
ALTER TABLE [dbo].[Table1] WITH CHECK ADD CONSTRAINT [FK_constraint] FOREIGN KEY([field1], [field2])
REFERENCES [dbo].[Table2] ([field3], [field4])
GO
....
......--End of My code here......
rollback transaction
commit transaction
当我在ManagementStudio中运行脚本直到刚好在“回滚事务”上方时,如果发生一个简单的错误,例如被零除,我将运行“回滚事务”,所有更改都将毫无问题地回滚
但是,如果ALTERTABLE语句由于Table2不存在而失败,则会触发进一步的错误
信息1767,16级,状态0,第2行
外键“FK_约束”引用了无效的表“dbo.Table2”
Msg 1750,第16级,第0状态,第2行
无法创建约束。请参阅前面的错误
信息1767,16级,状态0,第2行
外键“FK_uxxxxxx”引用了无效的表“Table1”
当我运行“回滚事务”时,我得到了这样一条错误消息“回滚事务请求没有相应的开始事务”。这很愚蠢,因为我在上面有一个开始事务
请告诉我出了什么问题。任何帮助都将不胜感激。使用SQLServer2008
编辑:
我补充说
SELECT @@TRANCOUNT;
“使用CHECK ADD CONSTRAINT更改表[dbo].[Table1]之前和之后”
结果分别为1和0。alter table在出现错误时自动回滚我的事务!?我无法理解这一点。发生这种情况的唯一方法是在该SPID中没有打开的事务。 就这样。没有公开交易的唯一方法是:
- 在旧事务提交或回滚后,您从未启动过新事务
- 你有另一个提交或回滚到你没有注意到的地方
- 某些东西导致连接中断或从spid外部强制回滚(如另一个会话中的
命令)kill
您没有提供太多的代码。查询中是否有未显示的错误捕获或任何其他条件逻辑?据我所知,ALTER TABLE命令将创建自己的新事务,当它失败时,将回滚该事务。进程内的一次回滚将导致该进程内所有打开的事务回滚。因此,您看到了错误,因为ALTER TABLE语句的失败是在您尝试执行之前隐式回滚事务 通过检查代码中的@TRANCOUNT,并仅在其不为零时调用rollback,您可以很容易地确认这一点,因为:
create table z
(
i int identity(1,1) not null,
zzz int not null
);
当你尝试下列方法时
begin try
begin transaction
alter table z drop column aaa;
commit tran;
end try
begin catch
print 'hello';
SELECT
ERROR_NUMBER() as ErrorNumber,
ERROR_MESSAGE() as ErrorMessage;
IF (XACT_STATE()) = -1
BEGIN
PRINT
N'The transaction is in an uncommittable state. ' +
'Rolling back transaction.'
ROLLBACK TRANSACTION;
END;
end catch
print 'reached';
..可以捕捉到错误:
ErrorNumber ErrorMessage
4924 ALTER TABLE DROP COLUMN failed because column 'aaa' does not exist in table 'z'.
但是试着改变altertablez,删除列aaa代码>至更改表z添加zzz int代码>,Sql Server可以捕获错误
每个表中的列名必须是唯一的。表中的列名“zzz”
多次指定了“z”
…但不会将控制权交还给您,不会触发捕捉块。似乎没有硬性规定什么错误是可以捕捉的,什么错误不是
为了说明区别,下面是代码可以捕获的错误
这里有一个代码无法捕获的错误,它与您的问题类似
注意这里没有网格(通过选择ERROR\u NUMBER()作为ErrorNumber,ERROR\u MESSAGE()作为ErrorMessage;
)。这意味着,Sql Server在检测到异常后不会将控件返回给您
也许您可以在此处查看其他可能有帮助的详细信息:
有关错误处理,请参阅本指南
顺便说一下,在Postgresql上,您的代码可以捕获所有类型的DDL错误
do $$
begin
-- alter table z drop column aaa;
alter table z add zzz int;
exception when others then
raise notice 'The transaction is in an uncommittable state. '
'Transaction was rolled back';
raise notice 'Yo this is good! --> % %', SQLERRM, SQLSTATE;
end;
$$ language 'plpgsql';
下面是altertablezdropcolumnaaa的dev呈现的错误消息:
以下是altertablezaddzzzint的开发人员呈现的错误消息;顺便说一句,在Sql Server中,当它在这种类型的语句中出错时,它不会将控件返回给您,因此您的CATCH
部分有时有用,有时无用
来自ALTER TABLE
语句的错误是一个编译错误,而不是运行时错误,因此该语句所在的整个批永远不会执行。我猜在开始事务
和更改表
之间没有GO
——因此开始事务
从未执行过,SQL Server告诉您的是完全正确的
尝试在开始事务之后立即添加一个GO
我认为对于使用DDL错误严重性处理的Sql Server处理,您无能为力,其中一些由Sql Server本身自动处理(例如强制回滚事务)
您所能做的就是让脚本代码处理它,并向脚本用户提供描述性错误
例如:
-- drop table thetransformersmorethanmeetstheeye
-- select * from thetransformersmorethanmeetstheeye
-- first batch begins here
begin tran
create table thetransformersmorethanmeetstheeye(i int); -- non-erring if not yet existing
-- even there's an error here, @@ERROR will be 0 on next batch
ALTER TABLE [dbo].[Table1] WITH CHECK ADD CONSTRAINT [FK_constraint] FOREIGN KEY([field1], [field2])
REFERENCES [dbo].[Table2] ([field3], [field4]);
go -- first batch ends here
-- second batch begins here
if @@TRANCOUNT > 0 begin
PRINT 'I have a control here if things needed be committed or rolled back';
-- @@ERROR is always zero here, even there's an error before the GO batch.
-- @@ERROR cannot span two batches, it's always gets reset to zero on next batch
PRINT @@ERROR;
-- But you can choose whether to COMMIT or ROLLBACK non-erring things here
-- COMMIT TRAN;
-- ROLLBACK TRAN;
end
else if @@TRANCOUNT = 0 begin
PRINT 'Sql Server automatically rollback the transaction. Nothing can do about it';
end
else begin
PRINT 'Anomaly occured, @@TRANCOUNT cannot be -1, report this to Microsoft!';
end
-- second batch implicitly ends here
听起来像是在手动运行代码的各个部分。在发生第二组错误之前,是否可能没有突出显示开始事务
部分?是的,我正在手动运行它们。我确实在每次运行开始时突出显示了begin事务,我认为,这种DDL上的一个例外是,Sql Server会自动为您回滚事务;但真正令人失望的是,它不会将控制权交还给您,您的代码无法正常执行,例如,您的代码将无法检测事务级别(通过@@tracount
)我撒谎了!它不起作用。您可以使用:begin-tran;改变表格布拉赫添加布拉赫int;选择“废话”;rollback tran
它从不返回回滚,但它确实留下了一个打开的事务。@JNK:它没有留下一个打开的事务。若blah表中已经存在blah列,并且您确实存在:begintran;改变表格布拉赫添加布拉赫int;选择“废话”;回滚传输
,它会自动回滚,尽管不是通过您的回滚传输
代码,它是
-- drop table thetransformersmorethanmeetstheeye
-- select * from thetransformersmorethanmeetstheeye
-- first batch begins here
begin tran
create table thetransformersmorethanmeetstheeye(i int); -- non-erring if not yet existing
-- even there's an error here, @@ERROR will be 0 on next batch
ALTER TABLE [dbo].[Table1] WITH CHECK ADD CONSTRAINT [FK_constraint] FOREIGN KEY([field1], [field2])
REFERENCES [dbo].[Table2] ([field3], [field4]);
go -- first batch ends here
-- second batch begins here
if @@TRANCOUNT > 0 begin
PRINT 'I have a control here if things needed be committed or rolled back';
-- @@ERROR is always zero here, even there's an error before the GO batch.
-- @@ERROR cannot span two batches, it's always gets reset to zero on next batch
PRINT @@ERROR;
-- But you can choose whether to COMMIT or ROLLBACK non-erring things here
-- COMMIT TRAN;
-- ROLLBACK TRAN;
end
else if @@TRANCOUNT = 0 begin
PRINT 'Sql Server automatically rollback the transaction. Nothing can do about it';
end
else begin
PRINT 'Anomaly occured, @@TRANCOUNT cannot be -1, report this to Microsoft!';
end
-- second batch implicitly ends here