如何在SQL Server中重新显示相同的异常
我想在SQL Server中重新引发刚才在我的try块中发生的相同异常。我可以抛出相同的消息,但我想抛出相同的错误如何在SQL Server中重新显示相同的异常,sql,sql-server,database,tsql,exception,Sql,Sql Server,Database,Tsql,Exception,我想在SQL Server中重新引发刚才在我的try块中发生的相同异常。我可以抛出相同的消息,但我想抛出相同的错误 BEGIN TRANSACTION BEGIN TRY INSERT INTO Tags.tblDomain (DomainName, SubDomainId, DomainCode, Description) VALUES(@DomainName, @SubDomainId, @DomainCode, @Description)
BEGIN TRANSACTION
BEGIN TRY
INSERT INTO Tags.tblDomain (DomainName, SubDomainId, DomainCode, Description)
VALUES(@DomainName, @SubDomainId, @DomainCode, @Description)
COMMIT TRANSACTION
END TRY
BEGIN CATCH
declare @severity int;
declare @state int;
select @severity=error_severity(), @state=error_state();
RAISERROR(@@Error,@ErrorSeverity,@state);
ROLLBACK TRANSACTION
END CATCH
RAISERROR(@@Error,@ErrorSeverity,@state)代码>
这一行将显示错误,但我希望类似的功能。
这将引发错误号为50000的错误,但我希望抛出我正在传递的错误号@@error
我想在前端捕获此错误号
i、 e
我想要这个功能。这是使用raiseerror
无法实现的。我不想在后端给出自定义错误消息
RAISEERROR
当我传递要在catch中抛出的ErrorNo时,应该返回下面提到的错误
第14行
违反唯一密钥约束“UK_DomainCode”。无法插入
对象中的重复密钥
“Tags.tblDomain”。
声明已终止
编辑:
考虑到存储过程包含多个需要执行的查询,如果我希望在前端处理异常,那么不使用try-catch块有什么缺点?我认为您的选择是:
- 不要抓住错误(让它冒出来)
- 自订
在某些时候,SQL可能会引入一个reraise命令,或者只捕获某些错误的能力。但现在,使用一种变通方法。抱歉。好的,这是一个解决方法…:-)
如果您注意到catch块,它不会引发错误,而是返回实际的错误号(并且还会回滚事务)。现在在.NET代码中,而不是捕获
例外情况,如果使用ExecuteScalar(),则会获得所需的实际错误号并显示相应的数字
int errorNumber=(int)command.ExecuteScalar();
if(errorNumber=<SomeNumber>)
{
MessageBox.Show("Some message");
}
int errorNumber=(int)command.ExecuteScalar();
if(errorNumber=)
{
MessageBox.Show(“一些消息”);
}
希望这有帮助
EDIT:-请注意,如果您想获得受影响的记录数并尝试使用ExecuteOnQuery,上述解决方案可能不适用于您。否则,我想它会满足你的需要。让我知道。你不能:只有引擎可以抛出小于50000的错误。你所能做的就是抛出一个看起来像它的异常
这里的提问者使用客户端事务来做他想做的事情,我认为这有点愚蠢…从设计的角度来看,抛出带有原始错误号和自定义消息的异常有什么意义?在某种程度上,它打破了应用程序和数据库之间的接口契约。
如果希望捕获原始错误并在更高的代码中处理它们,请不要在数据库中处理它们。然后,当您捕获到异常时,您可以将呈现给用户的消息更改为您想要的任何内容。但我不会这么做,因为这会使您的数据库代码“嗯,不对”。正如其他人所说,您应该定义一组自己的错误代码(50000以上)并抛出它们。然后,您可以将完整性问题(“不允许重复值”)与潜在的业务问题分开处理——“邮政编码无效”、“未找到与标准匹配的行”等等。这里是一个功能完整的干净代码示例,用于在发生错误时回滚一系列语句并报告错误消息
begin try
begin transaction;
...
commit transaction;
end try
begin catch
if @@trancount > 0 rollback transaction;
throw;
end catch
SQL 2012之前
begin try
begin transaction;
...
commit transaction;
end try
begin catch
declare @ErrorMessage nvarchar(max), @ErrorSeverity int, @ErrorState int;
select @ErrorMessage = ERROR_MESSAGE() + ' Line ' + cast(ERROR_LINE() as nvarchar(5)), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE();
if @@trancount > 0 rollback transaction;
raiserror (@ErrorMessage, @ErrorSeverity, @ErrorState);
end catch
SQL 2012引入了throw语句:
如果指定的THROW语句没有参数,则它必须出现
在一个挡块里面。这将导致引发捕获的异常
在发生错误后,停止存储过程中的执行并将错误冒泡回调用程序的方法是,在可能引发错误的每个语句后面执行以下代码:
If @@ERROR > 0
Return
我自己很惊讶地发现,在一个错误之后,存储过程中的执行可以继续——没有意识到这会导致一些难以追踪的bug
这种类型的错误处理与Visual Basic 6(以前的.Net)并行。期待SQL Server 2012中的Throw命令。鉴于您尚未移动到2012,实现原始错误代码冒泡的一种方法是使用从catch块(重新)抛出的异常的文本消息部分。请记住,它可以包含一些结构,例如,调用方代码要在其catch块中解析的XML文本。在catch块中重新刷新(SQL2012之前的代码,对SQL2012和更高版本使用THROW语句):
当您希望在事务中执行SQL语句并将错误反馈给代码时,还可以为这些场景创建包装存储过程
CREATE PROCEDURE usp_Execute_SQL_Within_Transaction
(
@SQL nvarchar(max)
)
AS
SET NOCOUNT ON
BEGIN TRY
BEGIN TRANSACTION
EXEC(@SQL)
COMMIT TRANSACTION
END TRY
BEGIN CATCH
DECLARE @ErrorMessage nvarchar(max), @ErrorSeverity int, @ErrorState int
SELECT @ErrorMessage = N'Error Number: ' + CONVERT(nvarchar(5), ERROR_NUMBER()) + N'. ' + ERROR_MESSAGE() + ' Line ' + CONVERT(nvarchar(5), ERROR_LINE()), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE()
ROLLBACK TRANSACTION
RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState)
END CATCH
GO
-- Test it
EXEC usp_Execute_SQL_Within_Transaction @SQL = 'SELECT 1; SELECT 2'
EXEC usp_Execute_SQL_Within_Transaction @SQL = 'SELECT 1/0; SELECT 2'
EXEC usp_Execute_SQL_Within_Transaction @SQL = 'EXEC usp_Another_SP'
@Ashish Gupta:Thx寻求帮助,但我需要将异常从数据库抛出到前端,否则我会打开许多选项,如打印错误号()、返回错误号和1U建议。使用原始错误号和自定义消息抛出异常有什么意义?假设您希望直接在catch块中处理一个或两个特定(预期)错误,并将其余错误留给更高的层。因此,您需要能够重新显示未处理的异常。。。除了@Jenda解释的以外,我还喜欢使用try-catch来确保代码在异常发生后不会继续执行,就像在C#中的do一样:try{code();}catch(exception exc){log(exc);throw;}finally{cleanup();}
,其中抛出
将只引发原始异常及其原始上下文。我捕获错误并在SQL中重新抛出自定义错误消息,以添加详细信息,说明发生错误的行或其他详细信息(例如尝试插入的数据)在sql 2012中,您可以使用new THROW关键字Yes重新引发异常。当然,当被问到这个问题时,这是不可用的。更重要的是抓住并抓住它
begin try
begin transaction;
...
commit transaction;
end try
begin catch
declare @ErrorMessage nvarchar(max), @ErrorSeverity int, @ErrorState int;
select @ErrorMessage = ERROR_MESSAGE() + ' Line ' + cast(ERROR_LINE() as nvarchar(5)), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE();
if @@trancount > 0 rollback transaction;
raiserror (@ErrorMessage, @ErrorSeverity, @ErrorState);
end catch
BEGIN TRY
BEGIN TRANSACTION
...
COMMIT TRANSACTION
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION;
THROW
END CATCH
If @@ERROR > 0
Return
DECLARE
@ErrorMessage nvarchar(4000) = ERROR_MESSAGE(),
@ErrorNumber int = ERROR_NUMBER(),
@ErrorSeverity int = ERROR_SEVERITY(),
@ErrorState int = ERROR_STATE(),
@ErrorLine int = ERROR_LINE(),
@ErrorProcedure nvarchar(200) = ISNULL(ERROR_PROCEDURE(), '-');
SELECT @ErrorMessage = N'Error %d, Level %d, State %d, Procedure %s, Line %d, ' + 'Message: ' + @ErrorMessage;
RAISERROR (@ErrorMessage, @ErrorSeverity, 1, @ErrorNumber, @ErrorSeverity, @ErrorState, @ErrorProcedure, @ErrorLine)
CREATE PROCEDURE usp_Execute_SQL_Within_Transaction
(
@SQL nvarchar(max)
)
AS
SET NOCOUNT ON
BEGIN TRY
BEGIN TRANSACTION
EXEC(@SQL)
COMMIT TRANSACTION
END TRY
BEGIN CATCH
DECLARE @ErrorMessage nvarchar(max), @ErrorSeverity int, @ErrorState int
SELECT @ErrorMessage = N'Error Number: ' + CONVERT(nvarchar(5), ERROR_NUMBER()) + N'. ' + ERROR_MESSAGE() + ' Line ' + CONVERT(nvarchar(5), ERROR_LINE()), @ErrorSeverity = ERROR_SEVERITY(), @ErrorState = ERROR_STATE()
ROLLBACK TRANSACTION
RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState)
END CATCH
GO
-- Test it
EXEC usp_Execute_SQL_Within_Transaction @SQL = 'SELECT 1; SELECT 2'
EXEC usp_Execute_SQL_Within_Transaction @SQL = 'SELECT 1/0; SELECT 2'
EXEC usp_Execute_SQL_Within_Transaction @SQL = 'EXEC usp_Another_SP'