MW211 EXIT

devlog
MSSQL/トランザクション入れ子(3)実際の動き
2015年04月09日
トランザクションに入れ子があり、その途中で例外が発生した場合
どのように動くかを確認してみると…
┌──────────────────────────────────────┐
│BEGIN TRY                           ■                                      │
│    BEGIN TRANSACTION;              ■                                      │
│    -- ----------------------       ■                                      │
│    BEGIN TRY                       ■                                      │
│        BEGIN TRANSACTION;          ■                                      │
│        SELECT 1/0;  --例外発生     ★─┐◎例外発生                        │
│        COMMIT TRANSACTION;         □  │                                  │
│    END TRY                         □  │                                  │
│    BEGIN CATCH                     ■←┘                                  │
│        ROLLBACK TRANSACTION;       ■    ①外側のトランザクションも終了    │
│    END CATCH;                      ■                                      │
│    -- ----------------------       ■                                      │
│    COMMIT TRANSACTION;             ★─┐②終了済みのため例外              │
│END TRY                             □  │                                  │
│BEGIN CATCH                         ■←┘                                  │
│    ROLLBACK TRANSACTION;           ★─→③終了済みのため例外              │
│END CATCH;                          ■     (TRY-CATCH外のためメッセージ出力)│
└──────────────────────────────────────┘
入れ子の階層をさらに一つ足した場合は…
┌──────────────────────────────────────┐
│BEGIN TRY                           ■                                      │
│    BEGIN TRANSACTION;              ■                                      │
│    -- -------------------------    ■                                      │
│    BEGIN TRY                       ■                                      │
│        BEGIN TRANSACTION;          ■                                      │
│        -- ----------------------   ■                                      │
│        BEGIN TRY                   ■                                      │
│            BEGIN TRANSACTION;      ■                                      │
│            SELECT 1/0;  --例外発生 ★─┐◎例外発生                        │
│            COMMIT TRANSACTION;     □  │                                  │
│        END TRY                     □  │                                  │
│        BEGIN CATCH                 ■←┘                                  │
│            ROLLBACK TRANSACTION;   ■    ①外側のトランザクションも終了    │
│        END CATCH;                  ■                                      │
│        -- ----------------------   ■                                      │
│        COMMIT TRANSACTION;         ★─┐②終了済みのため例外              │
│    END TRY                         □  │                                  │
│    BEGIN CATCH                     ■←┘                                  │
│        ROLLBACK TRANSACTION;       ★─┐③終了済みのため例外              │
│    END CATCH;                      □  │                                  │
│    -- --------------------------   □  │                                  │
│    COMMIT TRANSACTION;             □  │                                  │
│END TRY                             □  │                                  │
│BEGIN CATCH                         ■←┘                                  │
│    ROLLBACK TRANSACTION;           ★─→④終了済みのため例外              │
│END CATCH;                          ■     (TRY-CATCH外のためメッセージ出力)│
└──────────────────────────────────────┘

ちなみ、トランザクションが終了済みのため例外が発生した場合の
エラーメッセージは以下の通りである
┌──────────────────────────────────────┐
│メッセージ 3903、レベル 16、状態 1                                          │
│ROLLBACK TRANSACTION 要求に対応する BEGIN TRANSACTION がありません。        │
├──────────────────────────────────────┤
│メッセージ 3902、レベル 16、状態 1                                          │
│COMMIT TRANSACTION 要求に対応する BEGIN TRANSACTION がありません。          │
└──────────────────────────────────────┘
TRY-CATCHで捕捉された場合は、エラーメッセージは抑止されるので
出力されるのは最後の一回だけとなる

見てのとおり、字面上ては「BEGIN」と「COMMIT(ROLLBACK)」が対になっていても
実際は、思いっきり破綻してしまうのだ。

なお、「PRINT @@TRANCOUNT;」で「BEGIN」の階層数が確認できるのだが、
これを見ていると、「BEGIN」の都度、順調にカウントアップしていくのだが、
最初の「ROLLBACK」で一気に「0」になってしまうのがわかる。
分類:MSSQL