外部キーは、この問題に対する最良のアプローチである可能性があります。ただし、テーブルのロック/トランザクションについて学習しようとしているので、当面は無視できることを願っています。
InnoDBデータベースに 2 つのテーブルがあるcategories
としましょうjokes
。そして、私はPHP/MySQLiを使用して作業を行っています。テーブルは次のようになります。
CATEGORIES
id (int, primary, auto_inc) | category_name (varchar[64])
============================================================
1 knock, knock
JOKES
id (int, primary, auto_inc) | category_id (int) | joke_text (varchar[255])
=============================================================================
empty
ここに 2 つの関数があり、それぞれが異なる接続によって同時に呼び出されています。呼び出しは次のとおりですdelete_category(1)
。add_joke(1,"Interrupting cow. Interrup-MOOOOOOOO!")
function delete_category($category_id) {
// only delete the category if there are no jokes in it
$query = "SELECT id FROM jokes WHERE category_id = '$category_id'";
$result = $conn->query($query);
if ( !$result->num_rows ) {
$query = "DELETE FROM categories WHERE id = '$category_id'";
$result = $conn->query($query);
if ( $conn->affected_rows ) {
return true;
}
}
return false;
}
function add_joke($category_id,$joke_text) {
$new_id = -1;
// only add the joke if the category exists
$query = "SELECT id FROM categories WHERE id = '$category_id'";
$result = $conn->query($query);
if ( $result->num_rows ) {
$query = "INSERT INTO jokes (joke_text) VALUES ('$joke_text')";
$result = $conn->query($query);
if ( $conn->affected_rows ) {
$new_id = $conn->insert_id;
return $new_id;
}
}
return $new_id;
}
ここで、SELECT
両方の関数のステートメントが同時に実行され、そこから処理が進むとdelete_category
、カテゴリを削除しても問題ないと判断add_joke
され、ジョークを既存のカテゴリに追加しても問題ないと判断されるため、空のcategories
テーブルが得られます。および、joke
存在しない を参照するテーブル内のエントリcategory_id
。
外部キーを使用しない場合、この問題をどのように解決しますか?
これまでの私の最善の考えは、次のことを行うことです。
1)"LOCK TABLES categories WRITE, jokes WRITE"
の開始時delete_category
。ただし、私は InnoDB を使用しているため、テーブル全体 (特に頻繁に使用される主要なもの) をロックすることは避けたいと思っています。
2)add_joke
トランザクションを作成し、レコードを挿入した"SELECT id FROM categories WHERE id = '$category_id'"
後に実行する。その時点で存在しない場合は、トランザクションをロールバックします。ただし、 の 2 つのSELECT
ステートメントはadd_joke
異なる結果を返す可能性があるため、よく知らないトランザクション分離レベルを調べる必要があると思います。
これらの両方を行った場合、期待どおりに機能するはずです。それにもかかわらず、私はより多くの情報に基づいた意見を聞きたいと思っています。ありがとう。