SQL 事务错误:当前事务无法提交,不支持写入日志文件的操作 [英] SQL Transaction Error: The current transaction cannot be committed and cannot support operations that write to the log file

查看:178
本文介绍了SQL 事务错误:当前事务无法提交,不支持写入日志文件的操作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了与 当前事务无法提交,无法支持写入日志文件的操作,但我有一个后续问题.

I'm having a similar issue to The current transaction cannot be committed and cannot support operations that write to the log file, but I have a follow-up question.

那里的答案参考了在 Transact-SQL 中使用 TRY...CATCH,我稍后会回来...

The answer there references Using TRY...CATCH in Transact-SQL, which I'll come back to in a second...

我的代码(当然是继承的)具有简化形式:

My code (inherited, of course) has the simplified form:

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

我想我有足够的信息来玩它并自己弄清楚……不幸的是,重现该错误几乎是不可能的.所以我希望在这里提问有助于澄清我对问题和解决方案的理解.

I think I have enough information to just play with it and figure it out myself... unfortunately reproducing the error is proving damn near impossible. So I'm hoping that asking here will help clarify my understanding of the problem and solution.

这个存储过程间歇性地抛出这样的错误:

This stored procedure is, intermittently, throwing errors like this one:

error importing results for backtest 9649 error_number: 3930 error_message: 当前事务无法提交,不支持写入日志文件的操作.回滚事务.error_severity: 16 error_state 1 error_line: 217

error importing results for backtest 9649 error_number: 3930 error_message: The current transaction cannot be committed and cannot support operations that write to the log file. Roll back the transaction. error_severity: 16 error_state 1 error_line: 217

很明显错误来自第二个 catch 块

So obviously the error is coming from the 2nd catch block

基于我在中使用 TRY...CATCHTransact-SQL,我认为发生的事情是,当抛出异常时,使用XACT_ABORT 导致事务终止并回滚"......然后是 BEGIN CATCH 盲目地试图再次回滚.

Based on what I've read in Using TRY...CATCH in Transact-SQL, I think what's happening is that when the exception is thrown, the use of XACT_ABORT is causing the transaction to be "terminated and rolled back"... and then the first line of the BEGIN CATCH is blindly attempting to roll back again.

我不知道原始开发人员为什么启用 XACT_ABORT,所以我认为更好的解决方案(而不是删除它)是使用 XACT_STATE()仅在存在事务时回滚(<>0).这听起来合理吗?我错过了什么吗?

I don't know why the original developer enabled XACT_ABORT, so I'm thinking the better solution (than removing it) would be to use XACT_STATE() to only roll back if there is a transaction (<>0). Does that sound reasonable? Am I missing something?

此外,提到登录错误消息让我想知道:还有其他问题吗,可能是配置问题?我们在这个场景中使用 RAISEERROR() 会导致问题吗?在某些无法进行日志记录的情况下,是否会如错误消息所暗示的那样被记录?

Also, the mention of logging in the error message makes me wonder: Is there another problem, potentially with configuration? Is our use of RAISEERROR() in this scenario contributing to the problem? Does that get logged, in some sort of case where logging isn't possible, as the error message alludes to?

推荐答案

您总是需要检查 XACT_STATE(),与 XACT_ABORT 设置无关.我在 异常处理和嵌套事务:

You always need to check for XACT_STATE(), irrelevant of the XACT_ABORT setting. I have an example of a template for stored procedures that need to handle transactions in the TRY/CATCH context at Exception handling and nested transactions:

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

这篇关于SQL 事务错误:当前事务无法提交,不支持写入日志文件的操作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆