掲示板の作り方#8 スレッドデータを登録する
こんにちは。Suipediaです(∩´∀`)∩。
前回はユーザによって入力されたスレッドデータに不備がないかどうかをチェックする処理を実装しました。
不備があった場合は登録をせずにユーザに返すんでしたね。こうやって世の中のシステムたちはデータの不整合や不備を未然に防止しシステムが想定外の動きをしないようにしています。
今回はいよいよデータベースへの登録を行います。クライアントからサーバにデータは渡され、エラーチェックは済みました。さらにデータを格納する各種テーブルももう用意できています。
つまり、役者は揃った!!!やるぜ!!・・・って状態ですね(笑)
では早速参りましょう。
今回のゴール
今回はデータの登録を完了しますので、
このようにテーブルにデータが保存できる状態を目指します。
データを登録する
前回に続きまして、threadInsert.phpを開いてください。
残りのソースは細切れにお伝えするとキリが悪いので、一気に仕上げていただきます。以下のソースをエラーチェックの続きから書いてください。
/* ------------------------------ 登録処理 ------------------------------ */
try{
/* トランザクション制御 */
$dbh->beginTransaction();
/* スレッド管理テーブルへの登録 */
$sql="INSERT INTO bbs_thread(title,pass) VALUES (:title,:pass)";
$stmt = $dbh->prepare($sql);
$stmt->bindParam(':title', $title, PDO::PARAM_STR);
$stmt->bindParam(':pass', $pass, PDO::PARAM_STR);
$stmt->execute();
/* メッセージ管理テーブルへの登録 */
$sql="INSERT INTO bbs_message
(threadId,id,userType,name,message,iconId)
VALUES
((SELECT MAX(threadId) FROM bbs_thread),1,1,:name,:message,:iconId)";
$stmt = $dbh->prepare($sql);
$stmt->bindParam(':name', $name, PDO::PARAM_STR);
$stmt->bindParam(':message', $message, PDO::PARAM_STR);
$stmt->bindParam(':iconId', $icon, PDO::PARAM_STR);
$stmt->execute();
/* コミット(処理を確定) */
$dbh->commit();
/* 遷移用に最新スレッドIDを取得 */
$sql="SELECT MAX(threadId) FROM bbs_thread";
$stmt = $dbh->prepare($sql);
$stmt->execute();
$maxThreadId = $stmt->fetchColumn();
} catch (Exception $e) {
$dbh->rollBack();
echo "失敗しました。" . $e->getMessage();
}
/* 登録内容のスレッドに遷移させるため */
p($maxThreadId);
?>
はい、ありがとうございます。たぶん62~100行目辺りになっていると思います。
ではひとつずつ解説していきますね。
上記のソースでは大きく分けて4つのことをやっています。それが
・スレッドテーブルへの登録
・メッセージテーブルへの登録
・登録したスレッドのスレッドIDを取得
・取得したスレッドIDの出力
です。
スレッドテーブルへの登録
まず、スレッドテーブルへの登録ですが、このスレッド登録のタイミングでは・・・
枠で囲った2つのデータを同タイミングで登録する必要があります。スレッドはもちろんのこと、一発目のメッセージも登録します。
この前提を踏まえた上でソースを見ていきます。まず・・・
try{
/* トランザクション制御 */
$dbh->beginTransaction();
この部分です。まずtry(トライ)ステートメントですね。これは後に続くcatch(キャッチ)ステートメントとセットで使います。
プログラミングには予期せぬエラーが起こる可能性のある処理群はtry~catchで囲んで書くというルールがあります。
そうすることで実際に例外エラーが起きたときは処理の流れをcatchの中に強制的に遷移させることができます。
次の行を見てください。
/* トランザクション制御 */
$dbh->beginTransaction();
見慣れない言葉が出てきましたね。トランザクション。beginTransaction()なのでトランザクションの開始です。
トランザクションというのは不可分な処理の塊、と理解してください。処理の塊、ということはどこかに「この塊はここまでよ~」と明示するソースもあるはずです。それが
/* コミット(処理を確定) */
$dbh->commit();
これですね。86行目辺りにあると思います。
なぜこんなことをしているかというと、先ほど紹介した今回はスレッドテーブルとメッセージテーブルにデータを登録する、という話が関係しています。
この2つのテーブルへの登録処理はなんらかの異常事態によって処理が途中で終わるという事態をなんとしてでも避けたいんですね。避けねばならないんです、システム的に。
なぜなら仮にスレッドテーブルだけ登録され、メッセージテーブルが置き去りにされるようなことが起きるとデータに不整合が生じ、システムの正常なふるまいを維持できなくなる可能性があるからです。
つまり、スレッドテーブルにデータがある以上それに紐づくメッセージテーブルのデータも最低1件は存在する、というのがこのシステムの正しい振る舞い・あるべき姿です。
だから
・スレッドテーブルへの登録
・メッセージテーブルへの登録
という2つの処理を1つの塊として扱う必要があります。それをするのがトランザクションの役割です。
そして、トランザクションとセットで覚えておいてほしいのがcommit(コミット)とrollBack(ロールバック)です。
まずはコミットから。
スレッドテーブルとメッセージテーブルへの登録が無事に完了したらその時を以て初めてデータベースに対して処理の確定を通知します。それがコミットです。コミットをするまではまだ仮登録のようなものと思ってください。
次にロールバックです。
上記ソース中にロールバックが登場するのは・・・
} catch (Exception $e) {
$dbh->rollBack();
echo "失敗しました。" . $e->getMessage();
}
ここです。catchステートメントの中!
例えばスレッドテーブルへ登録し、これからメッセージテーブルへの登録もするぞ!という段階で予期せぬエラーが起きたとしましょう。その場合、仮登録状態にあるスレッドテーブルへの登録をなかったことにしなければなりません。
それをするのがrollBack(ロールバック)処理です。ロールバックをすると直前のトランザクション開始時点までデータの状態を戻してくれます。
・・・というのが
/* トランザクション制御 */
$dbh->beginTransaction();
このトランザクションに関連する説明です。
次にスレッドテーブルへの登録処理をみていきます。
/* スレッド管理テーブルへの登録 */
$sql="INSERT INTO bbs_thread(title,pass) VALUES (:title,:pass)";
$stmt = $dbh->prepare($sql);
$stmt->bindParam(':title', $title, PDO::PARAM_STR);
$stmt->bindParam(':pass', $pass, PDO::PARAM_STR);
$stmt->execute();
#6でSQLという言葉が出てきましたよね。データベースに対して操作をするための言語でした。
ここではその中のひとつを紹介します。それがINSERT句(いんさーとく)。
$sql="INSERT INTO bbs_thread(title,pass) VALUES (:title,:pass)";
データベースに干渉するときは基本的にSQLが必要になるので、これ以降の説明もデータを取得したり登録/更新するときはSQLが登場します。クエリという呼んだりすることも忘れないでください。
INSERT句は以下のような構文になっています。
INSERT INTO テーブル名 (項目名1,項目名2...) VALUES (登録値1,登録値2...);
今回使うINSERT句とも一致していますね。スレッドテーブルへの登録ではタイトルとパスワードの項目を登録対象とします。
スレッドテーブルにもっている項目はタイトル、パスワード、閉じるフラグ、無効フラグ、登録日、更新日の6つですが、必要ない項目はINSERT句に書く必要はありません。
勘のいい人は
肝心のスレッドIDは登録しないの?
と思ったかもしれません。
改めてここでスレッドIDについてお伝えします。結論から言うとスレッドIDはこちらがプログラムで指定しなくてもデータベースが勝手に採番してくれるんです。
そうなるようにテーブルを作成しました。これをみてください。
この記事が気に入ったらサポートをしてみませんか?