web-dev-qa-db-ja.com

EXECUTE後のトランザクション数は、BEGINステートメントとCOMMITステートメントの数の不一致を示しています。前のカウント= 1、現在のカウント= 0

Table1にデータをフィードし、Table1からColumn1値を取得し、Table2にフィードする2番目のストアドプロシージャを呼び出すストアドプロシージャを挿入しています。

しかし、2番目のストアドプロシージャを次のように呼び出すと、

Exec USPStoredProcName

次のようなエラーが表示されます。

EXECUTE後のトランザクション数は、BEGINステートメントとCOMMITステートメントの数の不一致を示しています。前のカウント= 1、現在のカウント= 0。

私はそのような他の質問の答えを読みましたが、コミット数がどこでめちゃくちゃになっているかを見つけることができません。

77
Vignesh Kumar A

TRY/CATCHブロックがある場合、考えられる原因は、トランザクション中止例外をキャッチして続行していることです。 CATCHブロックでは、常に XACT_STATE() を確認し、適切な中止およびコミット不能(ズーム)トランザクションを処理する必要があります。呼び出し元がトランザクションを開始し、caleeがデッドロック(トランザクションを中断した)にヒットした場合、呼び出し先はトランザクションが中断されたことを呼び出し元にどのように伝えますか?唯一の実行可能な方法は、例外を再発生させ、呼び出し側に状況を処理させることです。中止されたトランザクションを静かに飲み込んで、呼び出し元がまだ元のトランザクションにあると想定し続ける場合、混乱だけが保証できます(そして、あなたが得るエラーはエンジンがそれ自身を保護しようとする方法です)。

例外処理とネストされたトランザクション を確認することをお勧めします。これは、ネストされたトランザクションと例外で使用できるパターンを示しています。

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
go
93
Remus Rusanu

私もこの問題を抱えていました。私にとっては、その理由は

return
commit

の代わりに

commit
return   

1つのストアドプロシージャで。

47
seguso

これは通常、トランザクションが開始され、コミットされていないか、ロールバックされていないときに発生します。

ストアドプロシージャにエラーが発生した場合、例外処理がないために一部のランタイムエラーによりトランザクションが完了しないため、データベーステーブルがロックされる可能性があります。次のような例外処理を使用できます。 SET XACT_ABORT

SET XACT_ABORT ON
SET NoCount ON
Begin Try 
     BEGIN TRANSACTION 
        //Insert ,update queries    
     COMMIT
End Try 
Begin Catch 
     ROLLBACK
End Catch

ソース

ネストされたトランザクションを使用する場合、ROLLBACK操作は、最も外側のものを含むすべてのネストされたトランザクションをロールバックすることに注意してください。

これは、TRY/CATCHと組み合わせて使用​​すると、説明したエラーになる可能性があります。詳しくは こちら をご覧ください。

9
niklasolsn

これは、トランザクションを開いた後にストアドプロシージャでコンパイルエラーが発生した場合にも発生する可能性があります(テーブルが見つからない、列名が無効など)。

Remus Rusanuで概説されているロジックと同様のロジックを持つtry/catchを使用する2つのストアドプロシージャと、「ワーカー」プロシージャとラッパープロシージャを使用する必要がありました。ワーカーキャッチを使用して「通常の」エラーを処理し、ラッパーキャッチを使用してコンパイルエラーを処理します。

https://msdn.Microsoft.com/en-us/library/ms175976.aspx

TRY…CATCH構文の影響を受けないエラー

次のタイプのエラーは、CATCHブロックでは処理されませんそれらが同じ実行レベルで発生する場合 TRY…CATCHコンストラクトとして:

  • バッチの実行を妨げる構文エラーなどのコンパイルエラー
  • 遅延名前解決のためにコンパイル後に発生するオブジェクト名解決エラーなど、ステートメントレベルの再コンパイル中に発生するエラー。

うまくいけば、これは他の誰かがデバッグの数時間を節約するのに役立ちます...

2
Justin

私は同じエラーメッセージを持っていました、私の間違いはCOMMIT TRANSACTION行の終わりにセミコロンがあったことでした

2
Zsombor Zsuffa

トランザクションからこのステートメントを省略した後、一度このエラーが発生しました。

COMMIT TRANSACTION [MyTransactionName]
1
Ken Palmer

これは、C#コードからSPを呼び出す方法にも依存します。 SPが何らかのテーブルタイプの値を返す場合は、ExecuteStoreQueryでSPを呼び出します。SPが値を返さない場合は、ExecuteStoreCommandでSPを呼び出します。

1
Rajan Tikare

同じプロシージャ/クエリに複数のトランザクションが含まれていないことを確認してください。複数のトランザクションのうち、1つ以上がコミットされていない状態です。

私の場合、誤ってクエリにBEGIN TRANステートメントがありました

1
Sen Alexandru

広範囲にわたるデバッグの後、修正は単純な行方不明のスローでした。ロールバック後のキャッチ内のステートメント。これがないと、このいエラーメッセージが表示されます。

begin catch
    if @@trancount > 0 rollback transaction;
    throw; --allows capture of useful info when an exception happens within the transaction
end catch
0
hexpoint

私の意見では、受け入れられた答えはほとんどの場合過剰です。

エラーの原因は、多くの場合、エラーで明確に示されているように、BEGINとCOMMITの不一致です。これは以下を使用することを意味します:

Begin
  Begin
    -- your query here
  End
commit

の代わりに

Begin Transaction
  Begin
    -- your query here
  End
commit

開始後にトランザクションを省略すると、このエラーが発生します!

0
omostan