Ada*_*tle 36 sql-server transactions sql-server-2005
我遇到了类似的问题当前的事务无法提交,也无法支持写入日志文件的操作,但我有一个后续问题.
那里的答案在Transact-SQL中引用了使用TRY ... CATCH,我将在一秒钟内回过头来......
我的代码(当然继承)有简化形式:
SET NOCOUNT ON
SET XACT_ABORT ON
CREATE TABLE #tmp
SET @transaction = 'insert_backtest_results'
BEGIN TRANSACTION @transaction
BEGIN TRY
--do some bulk insert stuff into #tmp
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION @transaction
SET @errorMessage = 'bulk insert error importing results for backtest '
+ CAST(@backtest_id as VARCHAR) +
'; check backtestfiles$ directory for error files ' +
' error_number: ' + CAST(ERROR_NUMBER() AS VARCHAR) +
' error_message: ' + CAST(ERROR_MESSAGE() AS VARCHAR(200)) +
' error_severity: ' + CAST(ERROR_SEVERITY() AS VARCHAR) +
' error_state ' + CAST(ERROR_STATE() AS VARCHAR) +
' error_line: ' + CAST(ERROR_LINE() AS VARCHAR)
RAISERROR(@errorMessage, 16, 1)
RETURN -666
END CATCH
BEGIN TRY
EXEC usp_other_stuff_1 @whatever
EXEC usp_other_stuff_2 @whatever
-- a LOT of "normal" logic here... inserts, updates, etc...
END TRY
BEGIN CATCH
ROLLBACK TRANSACTION @transaction
SET @errorMessage = 'error importing results for backtest '
+ CAST(@backtest_id as VARCHAR) +
' error_number: ' + CAST(ERROR_NUMBER() AS VARCHAR) +
' error_message: ' + CAST(ERROR_MESSAGE() AS VARCHAR(200)) +
' error_severity: ' + CAST(ERROR_SEVERITY() AS VARCHAR) +
' error_state ' + CAST(ERROR_STATE() AS VARCHAR) +
' error_line: ' + CAST(ERROR_LINE() AS VARCHAR)
RAISERROR(@errorMessage, 16, 1)
RETURN -777
END CATCH
RETURN 0
Run Code Online (Sandbox Code Playgroud)
我想我有足够的信息来玩它并自己弄明白......不幸的是,重现这个错误几乎是不可能的.所以我希望这里的问题有助于澄清我对问题和解决方案的理解.
这个存储过程是间歇性地抛出这样的错误:
导入回测结果的错误9649 error_number:3930 error_message:当前事务无法提交,也不支持写入日志文件的操作.回滚交易.error_severity:16 error_state 1 error_line:217
所以很明显错误来自第二个阻塞块
基于我在Transact-SQL中使用TRY ... CATCH所读到的内容,我认为发生的事情是,当抛出异常时,使用XACT_ABORT会导致事务被"终止并回滚"......然后第一行BEGIN CATCH是盲目地试图再次回滚.
我不知道为什么原来的开发人员启用了XACT_ABORT,所以我认为更好的解决方案(而不是删除它)将仅用于XACT_STATE()在有事务(<>0)时回滚.这听起来合理吗?我错过了什么吗?
此外,提到登录错误消息让我想知道:还有其他问题,可能是配置?我们RAISEERROR()在这种情况下的使用是否会导致问题?是否会记录,在某种情况下无法进行日志记录,因为错误消息暗示了?
Rem*_*anu 41
您始终需要检查XACT_STATE(),与XACT_ABORT设置无关.我有一个存储过程模板的示例,需要在异常处理和嵌套事务处理 TRY/CATCH上下文中的事务:
create procedure [usp_my_procedure_name]
as
begin
set nocount on;
declare @trancount int;
set @trancount = @@trancount;
begin try
if @trancount = 0
begin transaction
else
save transaction usp_my_procedure_name;
-- Do the actual work here
lbexit:
if @trancount = 0
commit;
end try
begin catch
declare @error int, @message varchar(4000), @xstate int;
select @error = ERROR_NUMBER(),
@message = ERROR_MESSAGE(),
@xstate = XACT_STATE();
if @xstate = -1
rollback;
if @xstate = 1 and @trancount = 0
rollback
if @xstate = 1 and @trancount > 0
rollback transaction usp_my_procedure_name;
raiserror ('usp_my_procedure_name: %d: %s', 16, 1, @error, @message) ;
end catch
end
Run Code Online (Sandbox Code Playgroud)
小智 16
上面的讨论中有一些误解.
首先,无论事务的状态如何,您都可以随时ROLLBACK事务.所以你只需要在COMMIT之前检查XACT_STATE,而不是在回滚之前.
至于代码中的错误,您需要将事务放在TRY中.然后在你的CATCH中,你应该做的第一件事是:
IF @@TRANCOUNT > 0
ROLLBACK TRANSACTION @transaction
Run Code Online (Sandbox Code Playgroud)
然后,在上述声明之后,您可以发送电子邮件或任何需要的内容.(仅供参考:如果您在回滚之前发送电子邮件,那么您肯定会收到"无法写入日志文件"错误.)
这个问题是从去年开始的,所以我希望你现在已经解决了这个问题:-) Remus指出了你正确的方向.
根据经验......当出现错误时,TRY会立即跳转到CATCH.然后,当您在CATCH中时,可以使用XACT_STATE来决定是否可以提交.但是如果你总是想要捕获ROLLBACK,那么你根本不需要检查状态.
| 归档时间: |
|
| 查看次数: |
120279 次 |
| 最近记录: |