我编写了一个通过 调用另一个过程的过程link server,它具有 try catch 块,并且 catch 块在大多数错误的情况下都可以很好地工作,例如,当我想“将 NULL 值插入到不可为空的列”时,catch 块是成功执行并将错误结果记录到我的表中,但是当涉及到时link server timeout,catch 块不起作用,我不知道我在哪里错过了导致此问题的事情。
你可以看一下我的流程
AS
BEGIN
BEGIN TRY
BEGIN TRANSACTION
DECLARE @BeforeCall DATETIME,@AfterCall DATETIME,@DiffSec BIGINT,@CycleId BIGINT
DECLARE @TBL TABLE(Date INT,Time INT,Branch INT,Amount BIGINT)
----------------Get Last CycleId------------------------------------------
SELECT TOP 1 @CycleId=CycleId FROM dbo.BranchesResetDate_History
ORDER BY CycleId DESC
SET @CycleId=ISNULL(@CycleId,0)+1;
------------------------------------------------------------------
-----------------Get Reset Date--------------------------------------------
SET @BeforeCall=GETDATE()
INSERT INTO @TBL
(
Date,
Time,
Amount,
Branch
)
EXEC [AB_TO_FK].[xxxx].dbo.GetResetDate
SET @AfterCall=GETDATE()
SET @DiffSec=DATEDIFF(SECOND,@BeforeCall,@AfterCall)
-------------------------------------------------------------------
--------------------Log Execute Result To History------------------
INSERT INTO dbo.BranchesResetDate_History (Date,Time,Branch,Amount,InsertionDateTime,SecondsElapsed,CycleId)
SELECT Date,Time,Branch,Amount,dbo.DateTimeMDToSHD(GETDATE()),@DiffSec,@CycleId
FROM @TBL
--------------------------------------------------------------------
---------------------Insert Result To Main Table--------------------
INSERT INTO dbo.BranchesResetDate
(
ResetDate,
ResetTime,
BranchCode,
Amount,
InsertionDateTime
)
SELECT Date,
Time,
Branch,
Amount,
dbo.DateTimeMDToSHD(GETDATE())
FROM @TBL
-------------------------------------------------------------------
-------------Delete Duplicate Records------------------------------
DELETE res FROM (
SELECT id,ROW_NUMBER() OVER(PARTITION BY BranchCode,ResetDate,ResetTime,Amount ORDER BY ResetTime)rn FROM dbo.BranchesResetDate
) res WHERE res.rn>1
-------------------------------------------------------------------
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
IF @@TRANCOUNT>0
ROLLBACK TRANSACTION;
------------------------Log Exception------------------------------
INSERT INTO dbo.Proc_Exception (ErrorNumber,ErrorSeverity,ErrorState,ErrorProcedure,ErrorLine,ErrorMessage,DateTime)
SELECT ERROR_NUMBER(),
ERROR_SEVERITY(),
ERROR_STATE(),
ERROR_PROCEDURE(),
ERROR_LINE(),
ERROR_MESSAGE(),
dbo.DateTimeMDToSHD(GETDATE())
-------------------------------------------------------------------
END CATCH
END
GO
Run Code Online (Sandbox Code Playgroud)
当到达下面一行时
EXEC [AB_TO_FK].[xxxx].dbo.GetResetDate
Run Code Online (Sandbox Code Playgroud)
如果出现超时错误,catch 块不会执行,我只是收到此错误
链接服务器“AB_TO_FK”的 OLE DB 提供程序“SQLNCLI11”返回消息“查询超时已过期”
超时始终是由客户端(此处为具有链接服务器定义的服务器)引起的,客户端通过发送 TDS 注意事件来取消正在运行的查询。您看到的错误消息是本地生成的,并且(由于历史记录中丢失的原因)没有足够高的严重性来触发 CATCH 块或翻转@@错误。
推荐的解决方案是防止链接服务器超时。
可以通过扩展它,例如使用以下代码将远程查询超时设置为 0(无限等待):
sp_configure 'remote query timeout', 0
go
reconfigure with override
go
Run Code Online (Sandbox Code Playgroud)
根据此支持文章,或者导致远程调用失败并出现可捕获错误而不是超时。例如,您可以在程序中或在运行程序之前批量发送到远程服务器中设置 LOCK TIMEOUT 。
如果远程过程成功,则应返回 0。如果失败,则应返回某个非零值,如果由于超时而取消,则返回 null。所以你可以这样检查:
declare @r int
execute @r = [AB_TO_FK].[xxxx].dbo.GetResetDate
if (@r is null or @r <> 0)
begin
throw 51000, 'Linked Server Procedure failed. Possible timeout.', 1;
end
Run Code Online (Sandbox Code Playgroud)
您还可以捕获存储过程返回代码和结果集。如果它应该输出结果集,您还可以通过执行后检查表来确定它是否失败。例如
declare @t table (rc int)
declare @r int = -1
insert into @t(id)
execute @r = Loopback.tempdb.dbo.bar
if (@r is null or @r <> 0 or 0 = (select count(*) from @t) )
begin
throw 51000, 'Linked Server Procedure failed. Possible timeout.', 1;
end
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2287 次 |
| 最近记录: |