我正在编写一个存储过程,如果insert
失败,需要清理一些数据。我希望它执行清理,但如果此插入失败则返回原始错误(主要用于日志记录,因为我想确切看到insert
失败的原因)。基本上类似于throw;
中的C#
。有一个简单的方法吗?
BEGIN TRY
Insert into table (col1) values ('1")
END TRY
BEGIN CATCH
--do clean up here
--then throw original error
END TRY
这是可行/良好做法吗?在调用proc的应用程序代码中,我从应用程序的角度处理错误,但清理语句似乎更适合在proc中。
答案 0 :(得分:0)
我通常做这样的事情:
IF EXISTS (SELECT * FROM dbo.sysobjects WHERE id = object_id(N'[dbo].[procedure_name]') AND ObjectProperty(id, N'IsProcedure') = 1)
DROP PROCEDURE [dbo].[procedure_name]
GO
CREATE PROCEDURE [dbo].[procedure_name]
(
@param1 VARCHAR(100)
,@param2 INT
)
AS
/*
*******************************************************************************
<Name>
[procedure_name]
</Name>
<Purpose>
[Purpose]
</Purpose>
<Notes>
</Notes>
<OutsideRef>
Called From: [Called From]
</OutsideRef>
<ChangeLog>
Change No: Date: Author: Description:
_________ ___________ __________ _____________________________________
001 [DATE] [YOU] Created.
</ChangeLog>
*******************************************************************************
*/
BEGIN
SET NOCOUNT ON
SET XACT_ABORT OFF -- Allow procedure to continue after error
-- *****************************************
-- Parameter string. Used for error handling
-- *****************************************
DECLARE @ErrorNumber INT
,@ErrorMessage VARCHAR(400)
,@ErrorSeverity INT
,@ErrorState INT
,@ErrorLine INT
,@ErrorProcedure VARCHAR(128)
,@ErrorMsg VARCHAR(2000)
,@NestedProc BIT = 1
,@Params VARCHAR(255); -- String representing parameters, make it an appropriate size given your parameters.
--Be Careful of the CONVERT here, GUIDs (if you use them) need 36 characters, ints need 10, etc.
SET @Params = ''
+ CHAR(13) + '@param1 = ' + COALESCE(CONVERT(VARCHAR(100), @param1), 'NULL')
+ CHAR(13) + '@param2 = ' + COALESCE(CONVERT(VARCHAR(10), @param2), 'NULL')
BEGIN TRY
--If you're using transactions, and want an 'all or nothing' approach, use this so that
--you only start a single transaction in the outermost calling procedure (or handle
--that through your application layer)
IF @@TRANCOUNT = 0
BEGIN
SET @NestedProc = 0
BEGIN TRANSACTION
END
INSERT INTO [TABLE]
(
COL1
,COL2
)
VALUES
(
@param1
,@param2
);
--Commit the transaction if this is the outtermost procedure and if there is a transaction to rollback.
IF @@TRANCOUNT > 0 AND @NestedProc = 0
BEGIN
COMMIT TRANSACTION
END
END TRY
BEGIN CATCH
--Roll back the transaction if this is the outtermost procedure and if there is a transaction to rollback.
IF @@TRANCOUNT > 0 AND @NestedProc = 0
BEGIN
ROLLBACK TRANSACTION
END
-- Execute the error retrieval routine.
SELECT
@ErrorNumber = ERROR_NUMBER(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorProcedure = ERROR_PROCEDURE(),
@ErrorState = ERROR_STATE(),
@ErrorLine = ERROR_LINE(),
@ErrorMessage = ERROR_MESSAGE();
SET @ErrorMsg = 'Error Number : ' + CAST(@ErrorNumber AS VARCHAR(5)) + CHAR(13)
+ 'Procedure Name : ' + @ErrorProcedure + CHAR(13)
+ 'Procedure Line : ' + CAST(@ErrorLine AS VARCHAR(5)) + CHAR(13)
+ 'Error Message : ' + @ErrorMessage + CHAR(13)
+ 'Parameters : ' + CHAR(13) + @Params + CHAR(13);
--Raise the exception.
RAISERROR (@ErrorMsg, @ErrorSeverity, @ErrorState);
END CATCH
END
GO
这种类型的过程允许你对事务进行嵌套过程(只要所需的效果是如果在任何地方抛出错误,你最终会重新回到外部过程然后回滚)。我不认为这个模板处理的一个非常重要的场景是抛出严重到足以彻底终止该过程的错误。也许其他人可以在这方面插话。
答案 1 :(得分:0)
假设我们使用的表MyTable定义为
CREATE TABLE [dbo].[MyTable](
[Col1] [int] NOT NULL
) ON [PRIMARY]
我会使用类似下面的程序。
如果插入失败,代码将进入Catch块,可以执行和分配错误编号/消息的检查。
分配后,可以回滚事务并返回错误号/消息。
您可能需要根据您的操作更改RAISERROR错误行中的SQL Server错误号。
CREATE PROCEDURE [dbo].[zTestProc]
AS
BEGIN
SET NOCOUNT ON;
DECLARE
@LocalError INT,
@ErrorMessage VARCHAR(4000)
BEGIN TRY
BEGIN TRANSACTION TestTransaction
Insert into MyTable(col1) values ('01/01/2002')
COMMIT TRANSACTION TestTransaction
END TRY
BEGIN CATCH
SELECT @LocalError = ERROR_NUMBER(),
@ErrorMessage = ERROR_MESSAGE()
IF( XACT_STATE()) <>0
BEGIN
ROLLBACK TRANSACTION TestTransaction
END
RAISERROR ('TestSP: %d: %s', 16, 1, @LocalError, @ErrorMessage) ;
RETURN(0)
END CATCH
END
答案 2 :(得分:-1)
请尝试以下代码段。
DECLARE @errNum int
DECLARE @rowCount int
BEGIN TRY
INSERT INTO [TABLE] (COL1) VALUES ('1")
END TRY
BEGIN CATCH
SET @errNum = @@ERROR
SET @rowCount = @@ROWCOUNT
RAISEERROR(@errNum)
END CATCH