Sql server 如何回滚存储过程中的事务?
当内部SP尝试回滚事务时,它已完成,但出现错误: Msg 266,16级,状态2,程序ptest,第0行[批次开始行] 37]执行后的事务计数表示不匹配的 开始并提交语句。上一次计数=1,当前计数=0 是否可以回滚内部SP内的事务Sql server 如何回滚存储过程中的事务?,sql-server,tsql,Sql Server,Tsql,当内部SP尝试回滚事务时,它已完成,但出现错误: Msg 266,16级,状态2,程序ptest,第0行[批次开始行] 37]执行后的事务计数表示不匹配的 开始并提交语句。上一次计数=1,当前计数=0 是否可以回滚内部SP内的事务 IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ptest]') AND type in (N'P', N'PC')) BEGIN EXEC dbo.sp_ex
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ptest]') AND type in (N'P', N'PC'))
BEGIN
EXEC dbo.sp_executesql @statement = N'CREATE PROCEDURE [dbo].[ptest] AS'
END
GRANT EXECUTE on [dbo].[ptest] to public;
GO
ALTER PROCEDURE [dbo].[ptest]
@parrollback bit = 0
AS
BEGIN
SET NOCOUNT ON
SET XACT_ABORT OFF
select @@TRANCOUNT as '@@TRANCOUNT:[ptest] '
if @parrollback is not null and @parrollback>0
if @@TRANCOUNT>0 rollback tran;
END
GO
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[pcaller]') AND type in (N'P', N'PC'))
BEGIN
EXEC dbo.sp_executesql @statement = N'CREATE PROCEDURE [dbo].[pcaller] AS'
END
GRANT EXECUTE on [dbo].[pcaller] to public;
GO
ALTER PROCEDURE [dbo].[pcaller]
AS
BEGIN
SET NOCOUNT ON
begin tran
select @@TRANCOUNT as '@@TRANCOUNT: before [ptest]'
exec ptest 1
select @@TRANCOUNT as '@@TRANCOUNT: after [ptest] '
if @@TRANCOUNT>0 rollback tran;
END
GO
-------------
exec pcaller
/*
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ptest]') AND type in (N'P', N'PC'))
drop proc pcaller
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[ptest]') AND type in (N'P', N'PC'))
drop proc ptest
*/
尽量不要在子过程内处理父事务(当XACT_STATE()=-1时出现异常)。在启动事务的“执行”级别处理该事务 如果在父事务中执行过程,则创建保存点并在需要时回滚到该保存点。捕获子过程的执行结果,并在父级处理事务(如果父级是启动事务的父级)
创建或更改过程[dbo].[ptest]@parrollback位=0
作为
开始
不计较
将XACT_中止设置为OFF
声明@trancount INT=@@trancount;
如果@trancount=0
开始
开始交易;
结束
其他的
开始
保存事务MySavepoint;
结束
--做些事情。。。。。。。。。
--何时提交或检查错误
--假设@parrollback是主控制标准
如果@parrollback=1
开始
如果@trancount=0
开始
回滚事务;
返回(0);
结束
其他的
开始
回滚事务MySavePoint
申报表(1);
结束
结束
--为了测试的完整性,只需处理@parrollback 1
如果@trancount=0
开始
提交事务;
结束
返回(0);
结束
去
创建或更改过程dbo.pcaller
作为
开始
不计较
声明@ptestexec INT;
开始交易
选择@@TRANCOUNT作为“@@TRANCOUNT:在[ptest]之前”
EXEC@ptestexec=dbo.ptest@parrollback=1;
如果@ptestexec=1
开始
回滚事务
结束
其他的
开始
提交事务
结束
--在事务之外执行ptest
EXEC@ptestexec=dbo.ptest@parrollback=0;
选择@@TRANCOUNT作为trancount1;
EXEC@ptestexec=dbo.ptest@parrollback=1;
选择@@TRANCOUNT作为trancount2;
--在事务之外执行ptest
开始交易;
--在父事务中执行的ptest
EXEC@ptestexec=dbo.ptest@parrollback=0;
选择@@TRANCOUNT作为trancount3--ptest不影响父事务
提交事务——或回滚
结束
去
EXEC dbo.pcaller
去
在哪一行出现此错误?dbo.sp_executesql@statement=N'CREATE PROCEDURE[dbo].[pcaller]AS'
该语句的其余部分在哪里?BEGIN TRAN
没有COMMIT
;只有回滚
,如果@@TRANCOUNT
的值大于0
@Lamu:是,在调用者中开始TRAN,然后内部处理此事务回滚。最后trancount=0,但当我调用exec pcaller时,它会生成一个错误。
CREATE OR ALTER PROCEDURE [dbo].[ptest] @parrollback bit = 0
AS
BEGIN
SET NOCOUNT ON
SET XACT_ABORT OFF
DECLARE @trancount INT = @@TRANCOUNT;
IF @trancount = 0
BEGIN
BEGIN TRANSACTION;
END
ELSE
BEGIN
SAVE TRANSACTION MySavepoint;
END
--do stuff.........
--when it is time to commit or check for errors
--assume @parrollback is the main control criterium
IF @parrollback = 1
BEGIN
IF @trancount = 0
BEGIN
ROLLBACK TRANSACTION;
RETURN(0);
END
ELSE
BEGIN
ROLLBACK TRANSACTION MySavePoint
RETURN (1);
END
END
--just handle @parrollback <> 1, for completeness of the test
IF @trancount = 0
BEGIN
COMMIT TRANSACTION;
END
RETURN (0);
END
GO
CREATE OR ALTER PROCEDURE dbo.pcaller
AS
BEGIN
SET NOCOUNT ON
DECLARE @ptestexec INT;
BEGIN TRANSACTION
select @@TRANCOUNT as '@@TRANCOUNT: before [ptest]'
EXEC @ptestexec = dbo.ptest @parrollback = 1;
IF @ptestexec = 1
BEGIN
ROLLBACK TRANSACTION
END
ELSE
BEGIN
COMMIT TRANSACTION
END
--execute ptest, outside of a transaction
EXEC @ptestexec = dbo.ptest @parrollback = 0;
SELECT @@TRANCOUNT AS trancount1;
EXEC @ptestexec = dbo.ptest @parrollback = 1;
SELECT @@TRANCOUNT AS trancount2;
--execute ptest, outside of a transaction
BEGIN TRANSACTION;
--ptest executed in a parent transaction
EXEC @ptestexec = dbo.ptest @parrollback = 0;
SELECT @@TRANCOUNT AS trancount3; --ptest does not affect the parent transactions
COMMIT TRANSACTION --or rollback
END
GO
EXEC dbo.pcaller
GO