質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.92%

ロールバックの順序で納得のいかないことがあり、ご教示願いたいです。宜しくお願い致します。

解決済

回答 4

投稿

  • 評価
  • クリップ 0
  • VIEW 328

hungry

score 1

質問事項

WordPressのロールバックですが以下hogehoge()で成功しました。

私の理解によれば成功しないはずなのに、なぜ成功したのか?(つまり私の理解は何が間違いなのか?)を知りたいです。

hogehoge()

・まずfinaryが実行されますからロールバックの前にアンロックが処理されます。
・そしてアンロックしてしまってはロールバックは効かないはずです。

こう理解をしているので、以下hogehoge()でなぜ成功したのか疑問です。

function hogehoge() {
    global $wpdb;

    // トランザクションを開始
    $wpdb->query("START TRANSACTION"); // BEGINでもOK

    // 処理対象のテーブルをロック(table_name1, table_name2は適宜変更)
    $wpdb->query("LOCK TABLES table_name1 WRITE, table_name2 WRITE");

    try{
        // 更新処理
        $result = update_hogehoge();

        // エラー起こしてないか確認
        if( is_wp_error( $result ) ){
            $wpdb->query('ROLLBACK'); // Rollback
            // 必要があればエラー処理
            return;
        }

        $wpdb->query('COMMIT'); // Commit

    }catch( Exception $e ){
        $wpdb->query('ROLLBACK'); // Rollback
        // エラー処理をもごもご

    }finally{
        // テーブルのロックを解除
        $wpdb->query('UNLOCK TABLES');
    }
}

確認事項1

まずfinaryが実行される

という理解は、このページによるものです。
https://qiita.com/eijenson/items/7e9e112e69b37f72353c

この理解は間違っているでしょうか?

確認事項2

アンロックしてしまってはロールバックは効かないはず

という理解は、以下コードが「//失敗」と「//成功」になったからです。

確認事項1が正しければ、hogehoge()ではfinaryにあるアンロックがまず処理されます。
それは以下「//失敗」の順序と同じはずです。しかしこれは失敗してしまいました。

逆にアンロックを後に処理した「//成功」が成功したので、こう理解しています。

この理解は間違っているでしょうか?

//失敗
global $wpdb;
if( $flag_rollback ){
    $wpdb->query('UNLOCK TABLES'); 
    $wpdb->query('ROLLBACK');                                
}else{
    $wpdb->query('COMMIT');
    $wpdb->query('UNLOCK TABLES'); 
}                                

//成功
global $wpdb;
if( $flag_rollback ){    
    $wpdb->query('ROLLBACK');
}else{
    $wpdb->query('COMMIT');
}
$wpdb->query('UNLOCK TABLES');    

ツールのバージョン

バージョンが関係あるかわかりませんが、WordPressは5.4で、PHPは7.3.0になります。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • hentaiman

    2020/07/22 08:31

    質問内容が「trycatchfinallyが僕の思った通りに動かないなんておかしい!」という意味合いが強いならphpマニュアルを確認しろと言うしかなく、「trycatchfinallyの動作が分からない!」という事なら各ブロックでechoしてみた?という状況確認になるが

    キャンセル

  • sazi

    2020/07/22 09:28

    当然、「InnoDB」ですよね?

    キャンセル

  • hungry

    2020/07/22 11:20

    はい、「InnoDB」でした。

    キャンセル

回答 4

checkベストアンサー

+1

function hoge(){
    try{
        return print('try');
    }
    catch(Exception $e){}
    finally{
        return print('finally');
    }
}
hoge();//tryfinally

try内でreturnが宣言されても実際に値を返す前に
finallyが実行されているだけで
決してfinallyが先に実行されているというわけではないです

PHPのマニュアルのcatchの項に書いてます

return 文は出現した時に評価されますが、 結果は finally ブロックが実行された後に返されます。 さらに、finally ブロックにも return 文が存在した場合は、 finally ブロックから値が返されます。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/07/22 11:58

    そういうことでしたか。引用までつけて頂きありがとうございます。助かりました。

    キャンセル

  • 2020/07/22 12:01

    皆様のおかげで確認事項1が間違いだとわかりましたが、確認事項2で「//失敗」がなぜ失敗し、「//成功」がなぜ成功するのかが疑問です…

    キャンセル

  • 2020/07/22 19:15

    UNLOCK TABLESで暗黙的にトランザクションがコミットされてしまうから
    ロールバックできないんじゃないですか

    キャンセル

  • 2020/07/22 20:41

    ああああーー!なるほどなるほどなるほど!納得ですね。どうもありがとうございます。とても助かりました。

    キャンセル

+1

・まずfinaryが実行されますからロールバックの前にアンロックが処理されます。

他の方の指摘にもありますが、認識誤りです。

・そしてアンロックしてしまってはロールバックは効かないはずです。

LOCK/UNLOCKは他のセッションとのトランザクションを制御するもので、
COMMIT/ROLLBACKは自身のトランザクションに関するものです

自身のトランザクションに限定した場合、それぞれは関係はありません。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/07/22 20:43

    こんばんは。どうやら「UNLOCK TABLESで暗黙的にトランザクションがコミットされてしまうから」というのが原因だったようです。

    キャンセル

  • 2020/07/22 22:00 編集

    UNLOCK に限らず、LOCKでもコミットのようですね。
    https://dev.mysql.com/doc/refman/5.6/ja/lock-tables-and-transactions.html
    それから、UNLOCKでコミットされるのはLOCKされている事が前提

    キャンセル

  • 2020/07/22 22:46

    なるほど、それは知れてよかったです。追加ありがとうございます。そうやってさらに調べると詳しくなれるんですね。度重なるやりとりにご親切に応じて頂き感謝です。

    キャンセル

0

何を確認したいのか、何が確認できたのかよくわかっていませんが、理解できていない機能 2 種類を同時に検証せず、一つづつ検証してみては?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

まずfinaryが実行されますからロールバックの前にアンロックが処理されます。

そんな処理にfinallyなんて名前をつけないでしょう。

という理解は、このページによるものです。
https://qiita.com/eijenson/items/7e9e112e69b37f72353c

そのページで解説されているのは、「try内でreturnするときにもfinallyの処理が行われるよ」ということです。

この理解は間違っているでしょうか?

明確に間違っています。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/07/22 10:03

    「try内でreturn」ですか?「catch内でreturn」の間違いでしょうか?
    なんにせよ、そのreturnの前にfinaryが処理されていますよね?↓

    finally句が実行されました。
    Catch句からのリターンです。

    これは、finaryが先に処理されているという理解にならないのでしょうか?

    キャンセル

  • 2020/07/22 10:30

    ええと、「まずfinallyが実行される」というあなたの文章は、「try-chatch-finally内で例外が発生した場合、catchでの処理より前に、まずfinallyが実行される」ということを言いたかったんですか? それで動作の理解は合っています。

    しかし、あまりに言葉足らず過ぎるでしょう。「ロールバックと書いてあるじゃないか」と言いたいのかもしれませんが、ロールバックは2カ所に書いてあるのでそれではわかりません。

    ちなみに、上記のリンク先のページの主題は「returnを書いても実行されたり、try句の中のreturnにまでカバーしてくれるとは思わなかった」です。

    キャンセル

  • 2020/07/22 11:17

    >それで動作の理解は合っています。

    なるほど。そうなりますと、hoge()の最後の

    }catch( Exception $e ){
    $wpdb->query('ROLLBACK'); // Rollback
    // エラー処理をもごもご

    }finally{
    // テーブルのロックを解除
    $wpdb->query('UNLOCK TABLES');
    }
    }

    は、

    $wpdb->query('UNLOCK TABLES');
    の後に
    $wpdb->query('ROLLBACK');
    が実行されてるという順序になりませんか?

    そしてこの順序は「//失敗」と同じだと思うのですが、この順序では失敗してしまいます。
    なぜなのでしょうか?

    キャンセル

  • 2020/07/22 11:20

    質問の仕方が悪かったといった反省よりも、自分の疑問の解消が優先されているようですね。付き合いきれないので放置しますね。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.92%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • トップ
  • PHPに関する質問
  • ロールバックの順序で納得のいかないことがあり、ご教示願いたいです。宜しくお願い致します。