Table1にデータをフィードし、Table1からColumn1値を取得し、Table2にフィードする2番目のストアドプロシージャを呼び出すストアドプロシージャを挿入しています。
しかし、2番目のストアドプロシージャを次のように呼び出すと、
Exec USPStoredProcName
次のようなエラーが表示されます。
EXECUTE後のトランザクション数は、BEGINステートメントとCOMMITステートメントの数の不一致を示しています。前のカウント= 1、現在のカウント= 0。
私はそのような他の質問の答えを読みましたが、コミット数がどこでめちゃくちゃになっているかを見つけることができません。
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
私もこの問題を抱えていました。私にとっては、その理由は
return
commit
の代わりに
commit
return
1つのストアドプロシージャで。
これは通常、トランザクションが開始され、コミットされていないか、ロールバックされていないときに発生します。
ストアドプロシージャにエラーが発生した場合、例外処理がないために一部のランタイムエラーによりトランザクションが完了しないため、データベーステーブルがロックされる可能性があります。次のような例外処理を使用できます。 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と組み合わせて使用すると、説明したエラーになる可能性があります。詳しくは こちら をご覧ください。
これは、トランザクションを開いた後にストアドプロシージャでコンパイルエラーが発生した場合にも発生する可能性があります(テーブルが見つからない、列名が無効など)。
Remus Rusanuで概説されているロジックと同様のロジックを持つtry/catchを使用する2つのストアドプロシージャと、「ワーカー」プロシージャとラッパープロシージャを使用する必要がありました。ワーカーキャッチを使用して「通常の」エラーを処理し、ラッパーキャッチを使用してコンパイルエラーを処理します。
https://msdn.Microsoft.com/en-us/library/ms175976.aspx
TRY…CATCH構文の影響を受けないエラー
次のタイプのエラーは、CATCHブロックでは処理されませんそれらが同じ実行レベルで発生する場合 TRY…CATCHコンストラクトとして:
- バッチの実行を妨げる構文エラーなどのコンパイルエラー。
- 遅延名前解決のためにコンパイル後に発生するオブジェクト名解決エラーなど、ステートメントレベルの再コンパイル中に発生するエラー。
うまくいけば、これは他の誰かがデバッグの数時間を節約するのに役立ちます...
私は同じエラーメッセージを持っていました、私の間違いはCOMMIT TRANSACTION行の終わりにセミコロンがあったことでした
トランザクションからこのステートメントを省略した後、一度このエラーが発生しました。
COMMIT TRANSACTION [MyTransactionName]
これは、C#コードからSPを呼び出す方法にも依存します。 SPが何らかのテーブルタイプの値を返す場合は、ExecuteStoreQueryでSPを呼び出します。SPが値を返さない場合は、ExecuteStoreCommandでSPを呼び出します。
同じプロシージャ/クエリに複数のトランザクションが含まれていないことを確認してください。複数のトランザクションのうち、1つ以上がコミットされていない状態です。
私の場合、誤ってクエリにBEGIN TRANステートメントがありました
広範囲にわたるデバッグの後、修正は単純な行方不明のスローでした。ロールバック後のキャッチ内のステートメント。これがないと、このいエラーメッセージが表示されます。
begin catch
if @@trancount > 0 rollback transaction;
throw; --allows capture of useful info when an exception happens within the transaction
end catch
私の意見では、受け入れられた答えはほとんどの場合過剰です。
エラーの原因は、多くの場合、エラーで明確に示されているように、BEGINとCOMMITの不一致です。これは以下を使用することを意味します:
Begin
Begin
-- your query here
End
commit
の代わりに
Begin Transaction
Begin
-- your query here
End
commit
開始後にトランザクションを省略すると、このエラーが発生します!