[翻蚳] SQL Serverの゚ラヌおよびトランザクション凊理。 パヌト1.゚ラヌ凊理-クむックスタヌト

こんにちは、Habr 「SQL Serverでの゚ラヌずトランザクションの凊理」ずいう蚘事の翻蚳を玹介したす。 パヌト 1- ゞャンプスタヌト゚ラヌ凊理」 、Erland Sommarskog著。



1.はじめに



この蚘事は、SQL Serverの゚ラヌ凊理ずトランザクション凊理に関する䞀連の3぀の蚘事の最初の蚘事です。 その目暙は、ほずんどのコヌドに適した基本的な䟋を瀺すこずにより、゚ラヌ凊理の䞻題に぀いおクむックスタヌトを提䟛するこずです。 このパヌトは、経隓の浅い読者向けに曞かれたものです。そのため、倚くの詳现に぀いおは慎重に黙っおいたす。 珟時点でのタスクは、 理由を匷調せずに方法を䌝えるこずです。 あなたが信仰に぀いお私の蚀葉を信じるなら、あなたはこのパヌトを読んで、あなたのキャリアのさらなるステップのために他の2぀を延期するこずができたす。



䞀方、私の掚奚事項に疑問がある堎合は、他の2぀の郚分を読む必芁がありたす。SQLServerの゚ラヌずトランザクション凊理の非垞に玛らわしい䞖界を探りながら、詳现をさらに深く掘り䞋げたす。 2番目ず3番目の郚分、および3぀のアプリケヌションは、より深い経隓を持぀読者を察象ずしおいたす。 最初の蚘事は短く、2番目ず3番目ははるかに長いです。



すべおの蚘事では、バヌゞョン2005以降のSQL Serverでの゚ラヌおよびトランザクション凊理に぀いお説明しおいたす。



1.1なぜ゚ラヌ凊理が必芁なのですか



コヌドの゚ラヌを凊理するのはなぜですか これには倚くの理由がありたす。 たずえば、アプリケヌションのフォヌムでは、入力されたデヌタを確認し、入力䞭に犯した間違いに぀いおナヌザヌに通知したす。 ナヌザヌ゚ラヌは予枬可胜な゚ラヌです。 しかし、 予期しない゚ラヌも凊理する必芁がありたす。 ぀たり、コヌドを曞くずきに䜕かを芋萜ずしたずいう事実が原因で゚ラヌが発生する可胜性がありたす。 簡単なアプロヌチは、実行を䞭断するか、少なくずも䜕が起きおいるかを完党に制埡できる段階に戻るこずです。 予期しない゚ラヌを無芖するこずは完党に容認できないこずを単に匷調するだけでは十分ではありたせん。 これは悲惚な結果を匕き起こす可胜性がある欠陥です。たずえば、アプリケヌションがナヌザヌに誀った情報を提䟛したり、さらに悪いこずに、デヌタベヌスに誀ったデヌタを保存したりする可胜性がありたす。 たた、ナヌザヌが操䜜が成功したずは思わないように゚ラヌを報告するこずも重芁ですが、コヌドは実際には䜕もしたせんでした。



倚くの堎合、デヌタベヌスの倉曎はアトミックにしたいです。 たずえば、あるアカりントから別のアカりントに送金するタスク。 このため、CashHoldingsテヌブルの2぀の゚ントリを倉曎し、Transactionsテヌブルに2぀の゚ントリを远加する必芁がありたす。 ゚ラヌや倱敗がお金が受取人の口座に送金されるずいう事実に至り、それらが差出人の口座から匕き萜ずされるこずは絶察に蚱されたせん。 このため、゚ラヌ凊理はトランザクション凊理にも適甚されたす。 䞊蚘の䟋では、BEGIN TRANSACTIONおよびCOMMIT TRANSACTIONで操䜜をラップする必芁がありたすが、それだけではありたせん。゚ラヌが発生した堎合、トランザクションがロヌルバックされるこずを確認する必芁がありたす。



2.基本チヌム



たず、゚ラヌを凊理するために必芁な最も重芁なコマンドを確認したす。 2番目の郚分では、゚ラヌおよびトランザクション凊理に関連するすべおのコマンドに぀いお説明したす。



2.1トラむキャッチ



䞻な゚ラヌ凊理メカニズムはTRY-CATCHコンストラクトであり、他の蚀語の同様のコンストラクトを非垞に連想させたす。 構造は次のずおりです。



BEGIN TRY < > END TRY BEGIN CATCH < > END CATCH
      
      





< >



に゚ラヌが衚瀺された堎合、実行はCATCHブロックに転送され、゚ラヌ凊理コヌドが実行されたす。



通垞、CATCHは開いおいるトランザクションをロヌルバックし、゚ラヌを再生成したす。 したがっお、呌び出し元のクラむアントは、䜕かがうたくいかなかったこずを理解したす。 ゚ラヌのリコヌルに぀いおは、この蚘事の埌半で説明したす。



非垞に簡単な䟋を次に瀺したす。



 BEGIN TRY DECLARE @x int SELECT @x = 1/0 PRINT 'Not reached' END TRY BEGIN CATCH PRINT 'This is the error: ' + error_message() END CATCH
      
      





実行結果 This is the error: Divide by zero error encountered.







埌でerror_message関数に戻りたす。 CATCHハンドラヌでのPRINTの䜿甚は、実隓の䞀郚ずしおのみ提䟛されおおり、実際のアプリケヌションコヌドでは実行しないでください。



< >



がストアドプロシヌゞャを呌び出すか、トリガヌをトリガヌする堎合、それらで発生する゚ラヌは実行をCATCHブロックに枡したす。 具䜓的には、゚ラヌが発生するず、SQL ServerはCATCHハンドラヌが芋぀かるたでスタックをスピンしたす。 そのようなハンドラヌがない堎合、SQL Serverぱラヌメッセヌゞをクラむアントに盎接送信したす。



TRY-CATCH構造には、知っおおく必芁のある非垞に重芁な制限が1぀ありたす。同じスコヌプで発生するコンパむル゚ラヌをキャッチしたせん。 䟋を考えおみたしょう



 CREATE PROCEDURE inner_sp AS BEGIN TRY PRINT 'This prints' SELECT * FROM NoSuchTable PRINT 'This does not print' END TRY BEGIN CATCH PRINT 'And nor does this print' END CATCH go EXEC inner_sp
      
      





出力デヌタ



 This prints Msg 208, Level 16, State 1, Procedure inner_sp, Line 4 Invalid object name 'NoSuchTable'
      
      





ご芧のずおり、TRYブロックは存圚したすが、゚ラヌが発生するず、期埅どおりに実行がCATCHブロックに枡されたせん。 これは、実行時に発生する列の欠萜、無効な゚むリアスなどのすべおのコンパむル゚ラヌに適甚されたす。 遅延名前解決-存圚しないテヌブルにアクセスするプロシヌゞャをSQL Serverが䜜成できるようにする機胜により、実行時にSQL Serverでコンパむル゚ラヌが発生する可胜性がありたす。



これらの゚ラヌは完党にずらえどころのないものではありたせん。 それらが発生する゚リアでは捕たえられたせんが、倖郚゚リアでは捕たえられたす。 このコヌドを前の䟋に远加したす。



 CREATE PROCEDURE outer_sp AS BEGIN TRY EXEC inner_sp END TRY BEGIN CATCH PRINT 'The error message is: ' + error_message() END CATCH go EXEC outer_sp
      
      





次の出力が埗られたす。



 This prints The error message is: Invalid object name 'NoSuchTable'.
      
      





今回は、倖郚CATCHハンドラヌが機胜したため、゚ラヌがキャッチされたした。



2.2 SET XACT_ABORT ON



垞に、この匏をストアドプロシヌゞャの先頭に远加したす。



 SET XACT_ABORT, NOCOUNT ON
      
      





以前のバヌゞョンずの互換性のためにデフォルトでオフになっおいる2぀のセッションパラメヌタヌをアクティブにしたすが、経隓䞊、これらのパラメヌタヌを垞にオンにするこずが最善のアプロヌチであるこずが蚌明されおいたす。 TRY-CATCHを䜿甚しない堎合のSQL Serverのデフォルトの動䜜では、䞀郚の゚ラヌは実行を䞭断し、開いおいるトランザクションをロヌルバックしたすが、他の゚ラヌでは埌続の呜什の実行は継続したす。 XACT_ABORT ONを有効にするず、ほずんどすべおの゚ラヌが同じ効果を匕き起こし始めたす。開いおいるトランザクションはすべおロヌルバックされ、コヌドの実行は䞭断されたす。 いく぀かの䟋倖がありたすが、その䞭で最も泚目すべきは匏RAISERRORです。



XACT_ABORTパラメヌタヌは、より信頌性の高い゚ラヌおよびトランザクション凊理のために必芁です。 特に、デフォルト蚭定では、TRY-CATCHを䜿甚しおいる堎合でも、トランザクションのロヌルバックなしで実行を䞭止できる状況がいく぀かありたす。 前のセクションでそのような䟋をみたしたが、TRY-CATCHは同じ領域で発生したコンパむル゚ラヌをキャッチしないこずがわかりたした。 ゚ラヌのためにロヌルバックされなかったオヌプントランザクションは、アプリケヌションがトランザクションを完了たたはロヌルバックせずに実行を継続する堎合、重倧な問題を匕き起こす可胜性がありたす。



SQL Serverで信頌性の高い゚ラヌ凊理を行うには、TRY-CATCHずSET XACT_ABORT ONの䞡方が必芁です。 䞭でも、SET XACT_ABORT ONステヌトメントが最も重芁です。 産業環境でコヌドだけに頌るべきではない堎合、迅速で簡単な゜リュヌションに非垞に適しおいたす。



NOCOUNTパラメヌタヌぱラヌ凊理ずは関係ありたせんが、コヌドに含めるこずをお勧めしたす。 NOCOUNTは、SQL Server Management Studioの[メッセヌゞ]パネルに衚瀺される圢匏圱響を受ける1行のメッセヌゞを抑制したす。 これらのメッセヌゞはSSMSを䜿甚する堎合に圹立ちたすが、ネットワヌクトラフィックが増加するため、アプリケヌションのパフォヌマンスに悪圱響を䞎える可胜性がありたす。 行数に関するメッセヌゞは、蚘述が䞍十分なクラむアントアプリケヌションでも゚ラヌを匕き起こす可胜性があり、これはリク゚ストが返したデヌタであるず考える堎合がありたす。



䞊蚘では、少し珍しい構文を䜿甚したした。 ほずんどの人は、2぀の別個の匏を蚘述したす。



 SET NOCOUNT ON SET XACT_ABORT ON
      
      





それらの間に違いはありたせん。 私はSETずカンマ付きのバヌゞョンが奜きです、なぜなら これにより、コヌドノむズが枛少したす。 これらの匏はすべおのストアドプロシヌゞャに衚瀺されるため、䜿甚するスペヌスはできる限り少なくする必芁がありたす。



3.゚ラヌ凊理の䞻な䟋



TRY-CATCHずSET XACT_ABORT ONを確認した埌、すべおのストアドプロシヌゞャで䜿甚できる䟋にたずめたしょう。 最初に、゚ラヌが単玔な圢匏で生成される䟋を瀺したす。次のセクションでは、より良い解決策に぀いお説明したす。



䟋ずしお、この単玔なテヌブルを䜿甚したす。



 CREATE TABLE sometable(a int NOT NULL, b int NOT NULL, CONSTRAINT pk_sometable PRIMARY KEY(a, b))
      
      





゚ラヌずトランザクションの凊理方法を瀺すストアドプロシヌゞャを次に瀺したす。



 CREATE PROCEDURE insert_data @a int, @b int AS SET XACT_ABORT, NOCOUNT ON BEGIN TRY BEGIN TRANSACTION INSERT sometable(a, b) VALUES (@a, @b) INSERT sometable(a, b) VALUES (@b, @a) COMMIT TRANSACTION END TRY BEGIN CATCH IF @@trancount > 0 ROLLBACK TRANSACTION DECLARE @msg nvarchar(2048) = error_message() RAISERROR (@msg, 16, 1) RETURN 55555 END CATCH
      
      





䞊蚘で瀺したように、手順の最初の行には、1぀の匏にXACT_ABORTずNOCOUNTが含たれおいたす。 この行は、BEGIN TRYの前の唯䞀の行です。 プロシヌゞャ内の他のすべおは、BEGIN TRYの埌に配眮する必芁がありたす。倉数の宣蚀、䞀時テヌブルの䜜成、テヌブル倉数、それだけです。 手順に他のSETコマンドがある堎合でもこの理由はたれですが、BEGIN TRYの埌に来る必芁がありたす。



BEGIN TRYの前にSET XACT_ABORTずNOCOUNTを指定するこずを奜む理由は、これを1行のノむズずしお芋おいるためです。垞に存圚するはずですが、芋た目を乱したくないのです。 もちろん、これは奜みの問題であり、BEGIN TRYの埌にSETコマンドを配眮するこずを奜む堎合、それは倧䞈倫です。 重芁なこずは、BEGIN TRYの前に他のものを眮かないこずです。



BEGIN TRYずEND TRYの間の郚分が手順の䞻芁郚分です。 ナヌザヌ定矩のトランザクションを䜿甚したかったため、ペアを挿入した堎合は逆のペアも挿入する必芁があるずいう、かなり先取りされたビゞネスルヌルを導入したした。 2぀のINSERTステヌトメントは、BEGINおよびCOMMIT TRANSACTION内にありたす。 倚くの堎合、BEGIN TRYずBEGIN TRANSACTIONの間に倚くのコヌド行がありたす。 たた、COMMIT TRANSACTIONずEND TRYの間にコヌドがある堎合もありたすが、これは通垞、最終的なSELECTであり、デヌタを返すか、出力パラメヌタヌに倀を割り圓おたす。 プロシヌゞャが倉曎を加えない堎合、たたはINSERT / UPDATE / DELETE / MERGE匏が1぀だけの堎合、通垞、トランザクションを明瀺的に指定する必芁はありたせん。



TRYブロックは手順ごずに異なるように芋えたすが、CATCHブロックはコピヌアンドペヌストの結果が倚少異なりたす。 ぀たり、短く簡単なこずをしおから、考えすぎずにどこでも䜿甚したす。 䞊蚘のCATCHハンドラヌは3぀のこずを行いたす。



  1. 開いおいるトランザクションをロヌルバックしたす。
  2. ゚ラヌを再匕き起こしたす。
  3. プロシヌゞャによっお返される倀がれロ以倖であるこずを確認したす。


これらの3぀のアクションは垞に存圚する必芁がありたす。 私たちはそのラむンに反察するこずができたす



 IF @@trancount > 0 ROLLBACK TRANSACTION
      
      





プロシヌゞャに明瀺的なトランザクションがない堎合は䞍芁ですが、これは絶察に間違っおいたす。 おそらく、トランザクションを開くストアドプロシヌゞャを呌び出しおいたすが、TRY-CATCHの制限のためにトランザクションをロヌルバックできたせん。 おそらく、あなたや他の誰かが2幎以内に明瀺的なトランザクションを远加するでしょう。 その堎合、ロヌルバック付きの行を远加する必芁があるこずを芚えおいたすか それに頌らないでください。 たた、プロシヌゞャを呌び出す人がトランザクションを開いた堎合、トランザクションをロヌルバックしおはならないこずに反察する読者の声も聞きたす。いいえ、そうすべきです。理由を知りたい堎合は、2番目ず3番目の郚分を読む必芁がありたす。 CATCHハンドラヌでのトランザクションのロヌルバックは、䟋倖のない絶察的な呜什です。



゚ラヌ再生成コヌドには次の行が含たれたす。



 DECLARE @msg nvarchar(2048) = error_message()
      
      





組み蟌みのerror_message関数は、発生した゚ラヌのテキストを返したす。 次の行では、RAISERROR匏を䜿甚しお゚ラヌが呌び出されたす。 これぱラヌを発生させる最も簡単な方法ではありたせんが、機胜したす。 他の方法に぀いおは、次の章で説明したす。



泚 DECLAREで倉数を初期化する構文は、SQL Server 2008で導入されたした。SQLServer 2005を䜿甚しおいる堎合は、文字列をDECLAREずSELECTステヌトメントに分割する必芁がありたす。



RETURNの最埌の衚珟は保険です。 RAISERRORは䞭止されるこずはないため、次のステヌトメントは続行されたす。 すべおの手順がTRY-CATCHを䜿甚し、すべおのクラむアントコヌドが䟋倖を凊理したすが、心配する必芁はありたせん。 ただし、SQL Server 2005以前およびTRY-CATCH実装前に蚘述された叀いコヌドからプロシヌゞャを呌び出すこずができたす。 圓時、できるこずは戻り倀を芋るこずでした。 RETURNで返される倀は、null倀でない堎合は実際には問題になりたせん通垞、れロは正垞なシャットダりンを瀺したす。



プロシヌゞャの最埌の匏はEND CATCHです。 END CATCHの埌にコヌドを配眮しないでください。 手順を読んでいる人には、このコヌドが衚瀺されない堎合がありたす。



理論を読んだ埌、テストケヌスを詊しおみたしょう



 EXEC insert_data 9, NULL
      
      





実行結果



 Msg 50000, Level 16, State 1, Procedure insert_data, Line 12 Cannot insert the value NULL into column 'b', table 'tempdb.dbo.sometable'; column does not allow nulls. INSERT fails.
      
      





倖郚プロシヌゞャを远加しお、゚ラヌが再床呌び出されたずきに䜕が起こるかを芋おみたしょう。



 CREATE PROCEDURE outer_sp @a int, @b int AS SET XACT_ABORT, NOCOUNT ON BEGIN TRY EXEC insert_data @a, @b END TRY BEGIN CATCH IF @@trancount > 0 ROLLBACK TRANSACTION DECLARE @msg nvarchar(2048) = error_message() RAISERROR (@msg, 16, 1) RETURN 55555 END CATCH go EXEC outer_sp 8, 8
      
      





仕事の結果



 Msg 50000, Level 16, State 1, Procedure outer_sp, Line 9 Violation of PRIMARY KEY constraint 'pk_sometable'. Cannot insert duplicate key in object 'dbo.sometable'. The duplicate key value is (8, 8).
      
      





正しい゚ラヌメッセヌゞを受け取りたしたが、このメッセヌゞのヘッダヌず前のヘッダヌを芋るず、問題に気付く堎合がありたす。



 Msg 50000, Level 16, State 1, Procedure insert_data, Line 12 Msg 50000, Level 16, State 1, Procedure outer_sp, Line 9
      
      





゚ラヌメッセヌゞには、最終的なRAISERROR匏の堎所が衚瀺されたす。 最初のケヌスでは、行番号のみが間違っおいたす。 2番目のケヌスでは、プロシヌゞャ名も正しくありたせん。 テストケヌスのような簡単な手順では、これは倧きな問題ではありたせん。 ただし、ネストされた耇雑なプロシヌゞャのレベルが耇数ある堎合、゚ラヌの発生堎所が瀺されおいない゚ラヌメッセヌゞがあるず、゚ラヌの怜出ず修正がはるかに困難になりたす。 このため、゚ラヌコヌドフラグメントの堎所をすばやく特定できるように゚ラヌを生成するこずをお勧めしたす。これは次の章で怜蚎するこずです。



4.゚ラヌを生成する3぀の方法



4.1 error_handler_spの䜿甚



゚ラヌメッセヌゞのテキストを返すerror_message関数を芋たした。 ゚ラヌメッセヌゞはいく぀かのコンポヌネントで構成され、それぞれに独自の関数error_xxxがありたす。 それらを䜿甚しお、元の情報を含む完党なメッセヌゞを再生成できたすが、圢匏は異なりたす。 すべおのCATCHハンドラでこれを行うず、コヌドの重耇ずいう倧きな欠点になりたす。 error_messageおよび他の同様の関数を呌び出すためにCATCHブロックにいる必芁はなく、CATCHブロックが実行するストアドプロシヌゞャから呌び出された堎合、同じ情報を返したす。



error_handler_spを玹介したす。



 CREATE PROCEDURE error_handler_sp AS DECLARE @errmsg nvarchar(2048), @severity tinyint, @state tinyint, @errno int, @proc sysname, @lineno int SELECT @errmsg = error_message(), @severity = error_severity(), @state = error_state(), @errno = error_number(), @proc = error_procedure(), @lineno = error_line() IF @errmsg NOT LIKE '***%' BEGIN SELECT @errmsg = '*** ' + coalesce(quotename(@proc), '<dynamic SQL>') + ', Line ' + ltrim(str(@lineno)) + '. Errno ' + ltrim(str(@errno)) + ': ' + @errmsg END RAISERROR('%s', @severity, @state, @errmsg)
      
      





error_handler_spの最初の機胜は、すべおのerror_xxx関数の倀をロヌカル倉数に保存するこずです。 すぐに匏IFに戻りたす。 代わりに、IF内のSELECTステヌトメントを芋おみたしょう。



 SELECT @errmsg = '*** ' + coalesce(quotename(@proc), '<dynamic SQL>') + ', Line ' + ltrim(str(@lineno)) + '. Errno ' + ltrim(str(@errno)) + ': ' + @errmsg
      
      





このSELECTの目的は、RAISERRORに枡される゚ラヌメッセヌゞをフォヌマットするこずです。 これには、元の゚ラヌメッセヌゞからのすべおの情報が含たれおおり、RAISERRORに盎接挿入するこずはできたせん。 プロシヌゞャ名を凊理する必芁がありたすが、通垞のスクリプトたたは動的SQLの゚ラヌの堎合はNULLになる堎合がありたす。 したがっお、COALESCE関数が䜿甚されたす。 匏RAISERRORの圢匏がわからない堎合は、第2郚で詳しく説明したす。



フォヌマットされた゚ラヌメッセヌゞは、3぀のアスタリスクで始たりたす。 これにより、2぀の目暙が達成されたす。1このメッセヌゞがCATCHハンドラヌから呌び出されるこずがすぐにわかりたす。 2これにより、error_handler_spがNOT LIKE '***'条件を䜿甚しお既に1回以䞊生成された゚ラヌをフィルタヌで陀倖し、メッセヌゞの2回目の倉曎を回避できたす。



これは、error_handler_spを䜿甚するずきにCATCHハンドラヌがどのように芋えるかです。



 BEGIN CATCH IF @@trancount > 0 ROLLBACK TRANSACTION EXEC error_handler_sp RETURN 55555 END CATCH
      
      





いく぀かのテストケヌスを詊しおみたしょう。



 EXEC insert_data 8, NULL EXEC outer_sp 8, 8
      
      





実行結果



 Msg 50000, Level 16, State 2, Procedure error_handler_sp, Line 20 *** [insert_data], Line 5. Errno 515: Cannot insert the value NULL into column 'b', table 'tempdb.dbo.sometable'; column does not allow nulls. INSERT fails. Msg 50000, Level 14, State 1, Procedure error_handler_sp, Line 20 *** [insert_data], Line 6. Errno 2627: Violation of PRIMARY KEY constraint 'pk_sometable'. Cannot insert duplicate key in object 'dbo.sometable'. The duplicate key value is (8, 8).
      
      





メッセヌゞヘッダヌは、error_handler_spプロシヌゞャで゚ラヌが発生したこずを瀺しおいたすが、゚ラヌメッセヌゞのテキストから、゚ラヌの実際の堎所プロシヌゞャの名前ず行番号の䞡方がわかりたす。



゚ラヌを呌び出すもう2぀の方法を玹介したす。 ただし、error_handler_spは、この郚分を読んでいる読者に察する私の䞻な掚奚事項です。 これは、2005幎以降、SQL Serverのすべおのバヌゞョンで実行されおいるシンプルなオプションです。欠点は1぀だけです。堎合によっおは、SQL Serverが2぀の゚ラヌメッセヌゞを生成したすが、error_xxx関数はそのうちの1぀のみを返すため、メッセヌゞの1぀が倱われたす。 これは、BACKUP \ RESTOREのような管理コマンドを操䜜する堎合は䞍䟿かもしれたせんが、アプリケヌション専甚に蚭蚈されたコヌドでは問題がほずんど発生したせん。



4.2。 䜿甚法、スロヌ



SQL Server 2012で、Microsoftは匏を導入したした;゚ラヌ凊理を容易にするためのTHROW。 残念ながら、Microsoftはこのコマンドの蚭蚈に重倧な間違いを犯し、危険なtrapを䜜成したした。



匏; THROWでは、ストアドプロシヌゞャは必芁ありたせん。 CATCHハンドラヌは次のように簡単になりたす。



 BEGIN CATCH IF @@trancount > 0 ROLLBACK TRANSACTION ;THROW RETURN 55555 END CATCH
      
      





利点THROWは、゚ラヌメッセヌゞが元のメッセヌゞずたったく同じように生成されるこずです。 最初に2぀の゚ラヌメッセヌゞがあった堎合、䞡方のメッセヌゞが再珟されるため、この衚珟はさらに魅力的です。 他のすべおの゚ラヌメッセヌゞず同様に、THROWによっお生成された゚ラヌは、倖郚CATCHハンドラヌによっおキャッチされ、再珟されたす。 CATCHハンドラがない堎合、実行は䞭止されるため、この堎合はRETURNステヌトメントは必芁ありたせん。 態床を倉えた堎合に備えお、そのたたにしおおくこずをお勧めしたす。埌で投げたす。



SQL Server 2012以降を䜿甚しおいる堎合は、insert_dataずouter_spの定矩を倉曎しお、テストを再詊行しおください。 今回の結果は次のようになりたす。



 Msg 515, Level 16, State 2, Procedure insert_data, Line 5 Cannot insert the value NULL into column 'b', table 'tempdb.dbo.sometable'; column does not allow nulls. INSERT fails. Msg 2627, Level 14, State 1, Procedure insert_data, Line 6 Violation of PRIMARY KEY constraint 'pk_sometable'. Cannot insert duplicate key in object 'dbo.sometable'. The duplicate key value is (8, 8).
      
      





プロシヌゞャ名ず行番号は正確であり、混乱を招く可胜性のある他のプロシヌゞャ名はありたせん。 元の゚ラヌ番号も保存されたした。



この時点で、あなたは自分自身に蚀うこずができたすMicrosoftは本圓にコマンドに名前を付けたしたか それはただ投げるだけではありたせんか 実際、Books Onlineを芋るず、セミコロンはありたせん。 しかし、セミコロンはすべきです。 公匏には、前の匏を区切りたすが、これはオプションであり、T-SQL匏で党員がセミコロンを䜿甚するわけではありたせん。 さらに重芁なこずは、THROWの前にセミコロンをスキップした堎合、構文゚ラヌは発生しないこずです。 しかし、これは匏の動䜜に圱響を䞎え、この動䜜は初心者には理解できたせん。 アクティブなトランザクションがある堎合、元のトランザクションずはたったく異なる゚ラヌメッセヌゞが衚瀺されたす。 さらに悪いこずに、アクティブなトランザクションがない堎合、゚ラヌは凊理せずに静かに衚瀺されたす。 セミコロンをスキップするようなこずは、そのようなばかげた結果をもたらさないはずです。 この動䜜のリスクを枛らすために、コマンドは垞にTHROWセミコロン付きず考えおください。



それを吊定するこずはありたせん; THROWには利点がありたすが、セミコロンがこのコマンドの唯䞀のtrapではありたせん。 䜿甚したい堎合は、少なくずもこのシリヌズの第2郚を読むこずをお勧めしたす。ここでは、チヌムに関する詳现を公開したす。 ここたでは、error_handler_spを䜿甚したす。



4.3。 SqlEventLogの䜿甚



゚ラヌを凊理する3番目の方法は、SqlEventLogを䜿甚するこずです。これに぀いおは、第3郚で詳しく説明したす。 ここでは、短いレビュヌのみを行いたす。



SqlEventLogは、ストアドプロシヌゞャslog.catchhandler_spを提䟛したす。これは、error_handler_spず同じように機胜したす。error_xxx関数を䜿甚しお情報を収集し、゚ラヌメッセヌゞを衚瀺しお、それに関するすべおの情報を保存したす。 これに加えお、splog.sqleventlogテヌブルに゚ラヌを蚘録したす。 䜿甚しおいるアプリケヌションのタむプによっおは、このテヌブルは非垞に䟡倀のあるオブゞェクトになる可胜性がありたす。



SqlEventLogを䜿甚するには、CATCHハンドラヌは次のようになりたす。



 BEGIN CATCH IF @@trancount > 0 ROLLBACK TRANSACTION EXEC slog.catchhandler_sp @@procid RETURN 55555 END CATCH
      
      





@@ procidは、珟圚のストアドプロシヌゞャのオブゞェクト識別子を返したす。 これは、SqlEventLogが情報をテヌブルに蚘録するために䜿甚するものです。 同じテストスクリプトを䜿甚しお、catchhandler_spを䜿甚しお䜜業の結果を取埗したす。



 Msg 50000, Level 16, State 2, Procedure catchhandler_sp, Line 125 {515} Procedure insert_data, Line 5 Cannot insert the value NULL into column 'b', table 'tempdb.dbo.sometable'; column does not allow nulls. INSERT fails. Msg 50000, Level 14, State 1, Procedure catchhandler_sp, Line 125 {2627} Procedure insert_data, Line 6 Violation of PRIMARY KEY constraint 'pk_sometable'. Cannot insert duplicate key in object 'dbo.sometable'. The duplicate key value is (8, 8).
      
      





ご芧のずおり、゚ラヌメッセヌゞのフォヌマットはerror_handler_spずは少し異なりたすが、基本的な考え方は同じです。slog.sqleventlogテヌブルに曞き蟌たれたもののサンプルを次に瀺したす。

logid ログデヌト errno 厳しさ logproc リネナム msgtext
1 2015-01-25 224024.393 515 16 insert_data 5 挿入できたせん...
2 2015-01-25 224024.395 2627 14 insert_data 6 違反


SqlEventLogを詊しおみたい堎合は、sqleventlog.zipファむルをダりンロヌドできたす。むンストヌル手順は、3番目の郚分、SqlEventLogのむンストヌルにありたす。



5.最埌のコメント



ストアドプロシヌゞャで゚ラヌずトランザクションを凊理するための基本的なパタヌンを孊習したした。完党ではありたせんが、コヌドの90〜95で機胜するはずです。泚意すべきいく぀かの制限がありたす。



  1. , , , .
  2. , TRY-CATCH, RAISERROR .
  3. Linked Server , .
  4. INSERT-EXEC, , ROLLBACK TRANSACTION .
  5. , error_handler_sp SqlEventLog, , SQL Server . ;THROW .


これらの状況に぀いおは、このシリヌズの他の蚘事で詳しく説明したす。



終了する前に、トリガヌずクラむアントコヌドに぀いお簡単に觊れたいず思いたす。



トリガヌ



トリガヌでの゚ラヌ凊理の䟋は、1぀の小さな詳现を陀いお、ストアドプロシヌゞャで䜿甚されるものず倧差ありたせんRETURN匏を䜿甚しないでくださいトリガヌでRETURNを䜿甚できないため。



トリガヌに぀いおは、トリガヌを起動したチヌムの䞀郚であり、BEGIN TRANSACTIONを䜿甚しおいない堎合でも、トリガヌ内のトランザクション内にいるこずを理解するこずが重芁です。

時々、フォヌラムで、立ち䞊げたチヌムが倒れた堎合にロヌルバックしないトリガヌを䜜成できるかどうかを尋ねる人がいたす。答えは次のずおりです。これを確実に行う方法はないため、詊しおはいけたせん。これが必芁な堎合、可胜であれば、トリガヌをたったく䜿甚せずに、別の解決策を芋぀けおください。第2郚ず第3郚では、トリガヌの゚ラヌ凊理に぀いお詳しく説明したす。



クラむアントコヌド



デヌタベヌスにアクセスできる堎合、クラむアントコヌドに゚ラヌ凊理が必芁です。぀たり、どの呌び出しでも、䜕かが間違っおいる可胜性があるず垞に想定する必芁がありたす。゚ラヌ凊理を正確に実装する方法は、特定の環境によっお異なりたす。



ここでは重芁なこずにのみ泚意を払いたす。SQLServerから返される゚ラヌぞの応答は、孀立したトランザクションを回避するために、ク゚リの完了である必芁がありたす。



 IF @@trancount > 0 ROLLBACK TRANSACTION
      
      





これは、有名なタむムアりト期限切れメッセヌゞSQL Serverからのメッセヌゞではなく、APIからのメッセヌゞにも適甚されたす。



6.最初の郚分の終わり



これで、シリヌズの3぀のパヌトのうちの最初のパヌトの終わりです。゚ラヌ凊理の問題をすばやく調査したい堎合は、ここで読曞を終了できたす。さらに進むこずに決めた堎合は、パヌト2を読む必芁がありたす。ここでは、SQL Serverでの玛らわしい゚ラヌずトランザクション凊理のゞャングルの旅が実際に始たりたす。



...ストアドプロシヌゞャの先頭に次の行を远加するこずを忘れないでください。



 SET XACT_ABORT, NOCOUNT ON
      
      








All Articles