###問題が発生する状況
以下test_insert_table2()
という関数は、wp_mains
とwp_sub1s
という2つのテーブルを更新し、片方でもエラーになれば両方共ROLLBACK
するという処理です。
この書き方はQiitaのこちらのページ(https://qiita.com/atomo/items/b96ad8808af7e5c8760b)を参考にしました。
ですが、wp_sub1s
でエラーを起こした場合、なぜかROLLBACK
が処理されずwp_mains
だけが更新されてしまうという問題が発生しました。
($main_id=999
の場合は文末の「テーブル構造」によって外部キーエラーが起こります。)
php
1$result2 = test_insert_table2(); 2var_dump($result2); 3 4function test_insert_table2(){ 5 global $wpdb; 6 $result = ['insert_id'=>null,'errors'=>[]]; 7 $user_id = get_current_user_id(); 8 9 // トランザクションとテーブルロック 10 $wpdb->query('START TRANSACTION'); 11 $wpdb->query('LOCK TABLES wp_mains WRITE, wp_sub1s WRITE'); 12 13 // 保存 14 $result_mains = $wpdb->insert( 'wp_mains', ['users_ID'=>$user_id,'content' =>'本文'], ['%d','%s'] ); 15 $main_id = 999; // 999 は存在しないのでエラーになる 16 //$main_id = $wpdb->insert_id; // これならエラーにならない 17 $result_sub1s = $wpdb->insert( 'wp_sub1s', ['mains_ID'=>$main_id,'title'=>'タイトル'], ['%d','%s'] ); 18 19 if($result_mains && $result_sub1s) { 20 $result['insert_id'] = $main_id; 21 $wpdb->query('COMMIT'); 22 $wpdb->query('UNLOCK TABLES'); 23 } 24 else { 25 $result['errors'] = ['$result_mains'=>$result_mains,'$result_sub1s'=>$result_sub1s]; 26 $wpdb->query('ROLLBACK'); 27 $wpdb->query('UNLOCK TABLES'); 28 } 29 return $result; 30}
###解決した方法
一晩格闘し、ふと何の根拠もなくトランザクションとテーブルロックの順番を下記のように逆にしたところ、無事ROLLBACK
が起こりました。
php
1 // $wpdb->query('START TRANSACTION'); 2 // $wpdb->query('LOCK TABLES wp_mains WRITE, wp_sub1s WRITE'); 3 // ↓ 4 $wpdb->query('LOCK TABLES wp_mains WRITE, wp_sub1s WRITE'); 5 $wpdb->query('START TRANSACTION');
質問事項
そこで質問なのですが、トランザクションとテーブルロックの順番は、
1つ目のコードのように「トランザクション→テーブルロック」ではなくて
2つ目のコードのように「テーブルロック→トランザクション」であっているのでしょうか?
MySQLのドキュメンテーションは読みましたが、この点についての言及がなく(あるのに読解できないせいか)、よく理解できません。
そして1つ目のコードでは、なぜwp_mains
だけが更新されROLLBACK
が処理されないのか、原因がわかる方がいらっしゃいましたら教えて頂けませんでしょうか。
テーブル構造
尚、上記wp_mains
とwp_sub1s
のテーブル構造は次のようになっているので、$main_id=999
の場合は外部キーエラーが起こるといった仕組みです。
php
1function test_create_table(){ 2 global $wpdb; 3 require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); // dbDelta() のため必要 4 5 // wp_mains テーブルを作成 6 $sql = "CREATE TABLE wp_mains ( 7 `ID` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT 8 ,`users_ID` BIGINT(20) UNSIGNED NOT NULL 9 ,`content` VARCHAR(1000) 10 ,PRIMARY KEY (`ID`) 11 ,FOREIGN KEY (`users_ID`) REFERENCES wp_users(`ID`) 12 );"; 13 add_option($table_name."_version", '1.0'); 14 dbDelta($sql); 15 16 // wp_sub1s テーブルを作成 17 $sql = "CREATE TABLE wp_sub1s ( 18 `mains_ID` BIGINT(20) UNSIGNED NOT NULL 19 ,`title` VARCHAR(50) NOT NULL 20 ,PRIMARY KEY (`mains_ID`) 21 ,FOREIGN KEY (`mains_ID`) REFERENCES wp_mains(`ID`) 22 );"; 23 add_option($table_name."_version", '1.0'); 24 dbDelta($sql); 25}
回答1件
あなたの回答
tips
プレビュー