我有一个存储过程,应该从数据库中删除模式。我从后端(使用C#)执行此存储过程。结果,如果删除成功或失败,我想接收布尔值。
var result = await session.Sp<bool>(c => c.spDeleteSchemaTotally, new { schemaName})
.SingleAsync()
.ConfigureAwait(false);
if (result)
{
tracer.Info("Deleted successfully");
}
else
{
tracer.Warn("Schema was not deleted appropriately");
}
存储过程:
ALTER PROCEDURE [dbo].[spDeleteSchemaTotally]
(@schemaName NVARCHAR(100))
AS
SET FMTONLY OFF
BEGIN TRY
UPDATE SchemaList
SET [Status] = 2 /* DELETING */
WHERE SchemaName = @schemaName
EXEC [dbo].[spDeleteSchema] @schemaName
EXEC [dbo].[spDeleteSchemaOwner] @schemaName
EXEC [dbo].[spDeleteSchemaUserRoles] @schemaName
UPDATE SchemaList
SET [Status] = 1 /* DELETED */,
SchemaName = SchemaName + '|deleted|' + FORMAT(GETUTCDATE(), 'MM-d-yyyy-hh:mm')
WHERE SchemaName = @schemaName
SELECT CAST(1 AS BIT);
END TRY
BEGIN CATCH
UPDATE SchemaList
SET [Status] = 3 /* ERRORED */
WHERE SchemaName = @schemaName
SELECT CAST(0 AS BIT);
END CATCH
我有一个表,其中存储了所有模式的列表。对于每个模式,我都有一些状态。每个模式都有一些自己的表,规则等。
但是由于某些原因,我注意到有时会发生一些错误,并且架构的状态为2(正在删除)。什么样的错误-我不知道,因为无法抓住这一刻。
从逻辑上讲,存储过程中会发生一些错误,但是为此,我有catch块。根据{{3}},某些内部存储过程内部的错误应由外部catch处理。因此,我认为以正确的方式编写的所有内容……但仍然存在不正确的行为。
有人可以指出我上述存储过程中处理错误的正确方法吗?
我正在使用SQL Server。
答案 0 :(得分:0)
如果每个内部存储过程确实具有Try-Catch构造,则需要向每个内部SP的Catch块中添加THROW命令。
它将向外部SP引发错误,您将可以对其进行跟踪。
这个想法是,如果内部带有Try-Catch块的SP中发生错误,则外部SP不会失败并且也不知道有错误。
答案 1 :(得分:0)
如果您的存储过程遵循这种框架,则应将您的错误传递回上游,返回到顶级调用者中的CATCH
块:
CREATE PROCEDURE y
AS
BEGIN
SELECT 1 / 0;
END;
GO
CREATE PROCEDURE x
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRY
EXEC y;
SELECT 0 AS result;
END TRY
BEGIN CATCH
PRINT error_message();
SELECT 1 AS result;
END CATCH;
END;
GO
EXEC x;
如果运行此命令,则过程y将生成“遇到零错误除以错误”错误,然后将其传播回过程x,在此进行处理和报告。
如果过程y中有一个TRY-CATCH
块,则将消耗该错误,并且什么也不会发送回过程x。
此外,您可以使用RETURN 0
或RETURN 1
返回存储过程的成功/失败状态,而不是使用SELECT
查询来执行此操作,这是更好的做法。如果您还有其他信息要传回,例如错误消息,那么您可以使用OUTPUT
参数执行此操作。
例如:
CREATE PROCEDURE y
AS
BEGIN
SELECT 1 / 0;
END;
GO
CREATE PROCEDURE x (
@message VARCHAR(512) OUTPUT)
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRY
EXEC y;
RETURN 0;
END TRY
BEGIN CATCH
SELECT @message = error_message();
RETURN 1;
END CATCH;
END;
GO
DECLARE @message VARCHAR(512);
DECLARE @ret INT;
EXEC @ret = x @message OUTPUT;
SELECT @ret, @message;
或者这是一个将内部异常重新传递回去的示例:
CREATE PROCEDURE y (
@message VARCHAR(512) OUTPUT)
AS
BEGIN
BEGIN TRY
SELECT 1 / 0;
RETURN 0;
END TRY
BEGIN CATCH
SELECT @message = 'Inner ' + ERROR_MESSAGE();
RETURN 1;
END CATCH;
END;
GO
CREATE PROCEDURE x (
@message VARCHAR(512) OUTPUT)
AS
BEGIN
SET NOCOUNT ON;
BEGIN TRY
DECLARE @ret INT;
EXEC @ret = y @message OUTPUT;
RETURN @ret;
END TRY
BEGIN CATCH
SELECT @message = 'Outer ' + ERROR_MESSAGE();
RETURN 1;
END CATCH;
END;
GO
DECLARE @message VARCHAR(512);
DECLARE @ret INT;
EXEC @ret = x @message OUTPUT;
SELECT @ret, @message;
运行该命令时,您将得到一个1的返回状态(异常),并显示错误消息:“遇到内部除以零的错误。”。因此,我们知道该错误实际上是由过程y引起的,即使过程x报告了该错误。