Sql server 如果远程存储过程失败,则返回
我正在创建一个存储过程。此存储过程运行本地存储过程和外部存储过程。为简单起见,我将调用本地服务器[local]和远程服务器[remote] 下面是一个简单的拓扑: 程序 在远程过程上使用事务时,会引发以下错误: OLE DB提供程序。。。返回消息合作伙伴事务管理器已禁用对远程/网络事务的支持 我发现我无法在本地为远程过程运行事务 如果此过程的任何部分失败,如何确保此过程将退出并回滚 注释 关于合并简单程序,其中一些单独使用。Sql server 如果远程存储过程失败,则返回,sql-server,sql-server-2008,stored-procedures,remote-server,Sql Server,Sql Server 2008,Stored Procedures,Remote Server,我正在创建一个存储过程。此存储过程运行本地存储过程和外部存储过程。为简单起见,我将调用本地服务器[local]和远程服务器[remote] 下面是一个简单的拓扑: 程序 在远程过程上使用事务时,会引发以下错误: OLE DB提供程序。。。返回消息合作伙伴事务管理器已禁用对远程/网络事务的支持 我发现我无法在本地为远程过程运行事务 如果此过程的任何部分失败,如何确保此过程将退出并回滚 注释 关于合并简单程序,其中一些单独使用。 您可以尝试将这两个存储过程执行到单独的try-CATCH块中,并检查C
您可以尝试将这两个存储过程执行到单独的try-CATCH块中,并检查CATCH块中对应的错误号。若错误号和您得到的错误号相同,您只需根据您的要求返回或提出错误
它是否会导致致命错误。请检查异常情况。您可以尝试将这两个存储过程执行到单独的try-CATCH块中,并检查CATCH块中对应的错误号。若错误号和您得到的错误号相同,您只需根据您的要求返回或提出错误
它是否会导致致命错误。请检查例外情况。我可能不太清楚您想要什么。如果需要整个monthlyRollUp SP在远程或本地过程发生故障时回滚,则需要分布式事务协调器。这将允许服务器传递有关事务的信息并协调提交。也就是说,两台服务器都必须指示获得了所有必要的锁,然后协调两台服务器上的提交,以便操作是自动的。以下是设置DTC的一个示例: 如果不希望远程过程参与/影响事务,可以尝试设置:
SET REMOTE_PROC_TRANSACTIONS OFF;
我以前没有使用过这种设置,所以我不确定它是否能满足您的需要。我可能不太清楚您想要什么。如果需要整个monthlyRollUp SP在远程或本地过程发生故障时回滚,则需要分布式事务协调器。这将允许服务器传递有关事务的信息并协调提交。也就是说,两台服务器都必须指示获得了所有必要的锁,然后协调两台服务器上的提交,以便操作是自动的。以下是设置DTC的一个示例: 如果不希望远程过程参与/影响事务,可以尝试设置:
SET REMOTE_PROC_TRANSACTIONS OFF;
我以前没有使用过这个设置,所以我不确定它是否能满足您的需要。我最简单的方法是
将返回值添加到远程进程。
将远程进程包装到事务中,并尝试在远程进程内捕获。如果发生错误,则返回false。
在本地存储过程上,如果为false,则不继续。
我也无法理解本地进程中多个BEGIN TRANS/COMMIT背后的原因。我的意思是,如果这是月末汇总,这不是一笔大交易,而不是一堆小交易吗?否则,trans1和trans2可能会成功提交,但3将失败,仅此而已
姓名由ofc组成:
CREATE PROC [remote].db.REMOTE_PROC (
@return_value int output
)
AS
BEGIN
SET XACT_ABORT ON;
BEGIN TRY
BEGIN TRANS
... do stuff ...
set @return_value = 1;
COMMIT;
END TRY
BEGIN CATCH
set @return_value = 0;
END CATCH
END
和本地程序
CREATE PROC [local].db.[monthlyRollUp] AS
BEGIN
SET XACT_ABORT ON;
declare @ret int;
EXECUTE [remote].dbo.REMOTE_PROC @return_value = @ret OUTPUT;
IF @ret = 0
PRINT 'ERROR :('
RETURN
END IF
BEGIN TRANS
-- one big transaction here
EXEC [LOCAL].[DB].[table].[sp1];
EXEC [LOCAL].[DB].[table].[sp2];
EXEC [LOCAL].[DB].[table].[sp3];
EXEC [LOCAL].[DB].[table].[sp4];
COMMIT;
END;
afair[remote].dbo.remote_PROC运行自己的事务空间,如果成功,则返回1。本地进程,检查返回值并决定是否继续
sp1、sp2、sp3和sp4都在一个事务中运行,因为每个事务都有多个事务对我来说没有多大意义 我认为最简单的方法是
将返回值添加到远程进程。
将远程进程包装到事务中,并尝试在远程进程内捕获。如果发生错误,则返回false。
在本地存储过程上,如果为false,则不继续。
我也无法理解本地进程中多个BEGIN TRANS/COMMIT背后的原因。我的意思是,如果这是月末汇总,这不是一笔大交易,而不是一堆小交易吗?否则,trans1和trans2可能会成功提交,但3将失败,仅此而已
姓名由ofc组成:
CREATE PROC [remote].db.REMOTE_PROC (
@return_value int output
)
AS
BEGIN
SET XACT_ABORT ON;
BEGIN TRY
BEGIN TRANS
... do stuff ...
set @return_value = 1;
COMMIT;
END TRY
BEGIN CATCH
set @return_value = 0;
END CATCH
END
和本地程序
CREATE PROC [local].db.[monthlyRollUp] AS
BEGIN
SET XACT_ABORT ON;
declare @ret int;
EXECUTE [remote].dbo.REMOTE_PROC @return_value = @ret OUTPUT;
IF @ret = 0
PRINT 'ERROR :('
RETURN
END IF
BEGIN TRANS
-- one big transaction here
EXEC [LOCAL].[DB].[table].[sp1];
EXEC [LOCAL].[DB].[table].[sp2];
EXEC [LOCAL].[DB].[table].[sp3];
EXEC [LOCAL].[DB].[table].[sp4];
COMMIT;
END;
afair[remote].dbo.remote_PROC运行自己的事务空间,如果成功,则返回1。本地进程,检查返回值并决定是否继续
sp1、sp2、sp3和sp4都在一个事务中运行,因为每个事务都有多个事务对我来说没有多大意义 如果您不能或不想使用DTC,并且不想使用CLR,则需要最后调用远程sp,因为您将无法回滚远程sp调用
SET NOCOUNT, XACT_ABORT ON
SET REMOTE_PROC_TRANSACTIONS OFF;
BEGIN TRY
DECLARE @ret INT
BEGIN TRAN
--Perform these in a transaction, so they all rollback together
EXEC [LOCAL].[DB].[table].[sp1]
EXEC [LOCAL].[DB].[table].[sp2]
EXEC [LOCAL].[DB].[table].[sp3]
EXEC [LOCAL].[DB].[table].[sp4]
--We call remote sp last so that if it fails we rollback the above transactions
--We'll have to assume that remote sp takes care of itself on error.
EXEC [REMOTE].[DB].[table].[sp]
COMMIT
END TRY
BEGIN CATCH
--We rollback
ROLLBACK
-- Insert error into log table
INSERT INTO [dbo].[log_table] (stamp, errorNumber,
errorSeverity, errorState, errorProcedure, errorLine, errorMessage)
SELECT GETDATE(), ERROR_NUMBER(), ERROR_SEVERITY(), ERROR_STATE(),ERROR_PROCEDURE(),
ERROR_LINE(), ERROR_MESSAGE()
END CATCH
如果本地sp依赖于远程存储过程的结果,则可以使用CLR
sp将需要外部访问权限并显式管理事务(基本上是一个滚动自己的DTC),但不需要两阶段提交。您实际上是在延迟远程提交
//这不是真正的两阶段提交,但是
//可能足以满足您的需要。边缘情况是,如果出现错误
//尝试提交远程事务时,无法回滚本地事务。
usingSqlConnection cnRemote=新建SqlConnection
{
试一试{
cnRemote.Open;
//启动远程事务并调用远程存储过程
SqlTransaction trnRemote=cnRemote.BeginTransaction远程传输;
SqlCommand cmdRemote=cnRemote.CreateCommand;
cmdRemote.Connection=cnRemote;
cmdRemote.Transaction=trnRemote;
cmdRemote.CommandType=CommandType.StoredProcess;
cmdRemote.CommandText='[dbo].[sp1]';
cmdRemote.ExecuteNonQuery;
usingSqlConnection cnLocal=new SqlConnectioncontext connection=true
{
cnLocal.Open;
SqlTransaction trnLocal=cnLocal.BeginTransactionLocalTran;
SqlCommand cmdLocal=cnLocal.CreateCommand;
cmdLocal.Connection=cnLocal;
cmdLocal.Transaction=trnLocal;
cmdLocal.CommandType=CommandType.StoredProcess;
cmdLocal.CommandText='[dbo].[sp1]';
cmdLocal.ExecuteNonQuery;
cmdLocal.CommandText='[dbo].[sp2]';
cmdLocal.ExecuteNonQuery;
cmdLocal.CommandText='[dbo].[sp3]';
cmdLocal.ExecuteNonQuery;
cmdLocal.CommandText='[dbo].[sp4]';
cmdLocal.ExecuteNonQuery;
//提交本地事务
trnLocal.Commit;
}
//提交远程传输
trnRemote.Commit;
}//试试看
捕获异常
{
//清理工作在这里进行。如果需要,回滚远程传输,记录错误,等等。
}
}
如果您不能或不想使用DTC,并且不想使用CLR,则需要最后调用远程sp,因为您将无法回滚远程sp调用
SET NOCOUNT, XACT_ABORT ON
SET REMOTE_PROC_TRANSACTIONS OFF;
BEGIN TRY
DECLARE @ret INT
BEGIN TRAN
--Perform these in a transaction, so they all rollback together
EXEC [LOCAL].[DB].[table].[sp1]
EXEC [LOCAL].[DB].[table].[sp2]
EXEC [LOCAL].[DB].[table].[sp3]
EXEC [LOCAL].[DB].[table].[sp4]
--We call remote sp last so that if it fails we rollback the above transactions
--We'll have to assume that remote sp takes care of itself on error.
EXEC [REMOTE].[DB].[table].[sp]
COMMIT
END TRY
BEGIN CATCH
--We rollback
ROLLBACK
-- Insert error into log table
INSERT INTO [dbo].[log_table] (stamp, errorNumber,
errorSeverity, errorState, errorProcedure, errorLine, errorMessage)
SELECT GETDATE(), ERROR_NUMBER(), ERROR_SEVERITY(), ERROR_STATE(),ERROR_PROCEDURE(),
ERROR_LINE(), ERROR_MESSAGE()
END CATCH
如果本地sp依赖于远程存储过程的结果,那么您可以使用CLR sp,因为它需要外部访问权限并显式管理事务(基本上是您自己的DTC,但不需要两阶段提交)。您实际上是在延迟远程提交
//这不是真正的两阶段提交,但是
//可能足以满足您的需要。边缘情况是,如果出现错误
//尝试提交远程事务时,无法回滚本地事务。
usingSqlConnection cnRemote=新建SqlConnection
{
试一试{
cnRemote.Open;
//启动远程事务并调用远程存储过程
SqlTransaction trnRemote=cnRemote.BeginTransaction远程传输;
SqlCommand cmdRemote=cnRemote.CreateCommand;
cmdRemote.Connection=cnRemote;
cmdRemote.Transaction=trnRemote;
cmdRemote.CommandType=CommandType.StoredProcess;
cmdRemote.CommandText='[dbo].[sp1]';
cmdRemote.ExecuteNonQuery;
usingSqlConnection cnLocal=new SqlConnectioncontext connection=true
{
cnLocal.Open;
SqlTransaction trnLocal=cnLocal.BeginTransactionLocalTran;
SqlCommand cmdLocal=cnLocal.CreateCommand;
cmdLocal.Connection=cnLocal;
cmdLocal.Transaction=trnLocal;
cmdLocal.CommandType=CommandType.StoredProcess;
cmdLocal.CommandText='[dbo].[sp1]';
cmdLocal.ExecuteNonQuery;
cmdLocal.CommandText='[dbo].[sp2]';
cmdLocal.ExecuteNonQuery;
cmdLocal.CommandText='[dbo].[sp3]';
cmdLocal.ExecuteNonQuery;
cmdLocal.CommandText='[dbo].[sp4]';
cmdLocal.ExecuteNonQuery;
//提交本地事务
trnLocal.Commit;
}
//提交远程传输
trnRemote.Commit;
}//试试看
捕获异常
{
//清理工作在这里进行。如果需要,回滚远程传输,记录错误,等等。
}
}
是否建议对第一个sp执行TRY…CATCH,检查错误号,然后执行第二个未嵌套的TRY…CATCH?是否建议对第一个sp执行TRY…CATCH,检查错误号,并执行第二次尝试…捕获不是嵌套的?当阅读有关此解决方案时,我唯一的犹豫是它已被弃用。它建议改为使用链接服务器,这已经到位。有可能让远程过程抛出一个错误,而本地过程捕获它吗?在阅读有关此解决方案的文章时,我唯一的犹豫是它已被弃用。它建议改为使用链接服务器,这已经到位。是否可能让远程过程仅仅抛出一个错误,而本地过程捕获它?远程过程不能包装到事务中,因为没有为此启用支持。我知道
ree建议将多个小程序组合在一起。如果您能够深入了解整个系统体系结构,即sql Server的版本和制造商,以及所使用的连接方法,这将对我们大有帮助。我在那里看到oledb,这对ms sql没有意义,而是使用链接服务器。然后将BEGIN TRANS/COMMIT放在远程存储过程中,这样事务对远程服务器来说是本地的。这一要求也不清楚。您还可以在两台服务器上编程两阶段提交,或者在两台服务器之间设置MS DTC和分布式事务。我将更新更多规范。正如前面的回答所建议的,我回答说,我对实施DTC犹豫不决,因为它已被弃用。弃用并不意味着一旦他们在monthership的深处按下红色按钮,DTC就会立即停止工作。相反,这意味着避免在新版本的产品上实施此解决方案:我已经更新了我的问题。我希望这有帮助。关于组合存储过程,它们在整个月内单独使用。远程过程不能包装到事务中,因为没有为此启用支持。我同意多个小程序应该结合在一起。如果您能提供关于整个系统架构的见解,即sql Server的版本和制造商,以及所使用的连接方法,这将对我们有很大帮助。我在那里看到oledb,这对ms sql没有意义,而是使用链接服务器。然后将BEGIN TRANS/COMMIT放在远程存储过程中,这样事务对远程服务器来说是本地的。这一要求也不清楚。您还可以在两台服务器上编程两阶段提交,或者在两台服务器之间设置MS DTC和分布式事务。我将更新更多规范。正如前面的回答所建议的,我回答说,我对实施DTC犹豫不决,因为它已被弃用。弃用并不意味着一旦他们在monthership的深处按下红色按钮,DTC就会立即停止工作。相反,这意味着避免在新版本的产品上实施此解决方案:我已经更新了我的问题。我希望这有帮助。关于组合存储过程,它们在整个月内单独使用。