人力検索はてな
モバイル版を表示しています。PC版はこちら
i-mobile

PHP5について質問です。


DB情報(table名:site)
id
title
url

このようなDBがあるとします。
このDBにユーザーが新しいサイト情報を入れていくページをPHP作っています。


すでに存在するURLの場合は登録を受け付けないようにしたいのですが、その場合はどのようなスクリプトを書けばいいでしょうか。


入力されたURLを$urlとします。
$sql = "SELECT * FROM site WHERE url = '$url'";
これでもし一件もヒットしなければその後INSERTで登録・・という流れでしょうか。


INSERTで登録する辺りは書けますので、その前の部分だけで構いません。
何か上手い書き方は無いでしょうか?


皆様よろしくお願いいたします。

●質問者: tokyosmash
●カテゴリ:インターネット ウェブ制作
✍キーワード:DB PHP SELECT SQL URL
○ 状態 :終了
└ 回答数 : 3/3件

▽最新の回答へ

1 ● chuken_kenkou
●50ポイント

SELECT文で存在するかどうか確認後、INSERTする方法もありますが、SELECT文とINSERT文を実行する間に、他のユーザにより先にINSERTされてしまうケースへの配慮が必要です。

重複チェックをアプリケーション側で行うのでなく、RDBMS側に任せてしまった方が、アプリケーション側での操作は楽になると思います。

RDBMSが何なのか分かりませんが、プライマリ・キー以外にユニーク・インデクスを定義できると思います。

主要なRDBMSでは、以下のようなSQLで定義します。

CREATE UNIQUE INDEX インデクス名 ON site(url) 

あとは、RDBMSで「重複エラー時に、どういうコードやメッセージが返却されるか?」を調べ、重複エラー時の処理をアプリケーション側で記述します。

◎質問者からの返答

回答ありがとうございます。以前よくお世話になっていたものです。DBはMySQL5を使っています。


いわゆる「トランザクション」と言うものなのでしょうか。金融系などクリティカルなシステムでは必須であるとか、そのような話を耳にした事があります。


DB側で重複チェックをするという発想は今までありませんでした。そのような機能があるのも知りませんでした。

質問文では「ユーザーが」と書いてありますが、実際には自分でURLを1件1件流し込んでいくようなシステムになります。つまりton-booさんの回答にあるようなAとBという二つのトランザクションが被ってしまう事はありえないはずです。

一通りMySQLにおけるトランザクション処理について調べてみて、もし敷居が高そうならばKUROXさんの回答を参考に簡単な処理で済ませてしまおうと思ってます。


トランザクションについて勉強になりました。ありがとうございました。


2 ● KUROX
●30ポイント

$sql = "SELECT count(*) as cnt FROM site WHERE url = '$url'";

面倒なら、count()を使ってレコード数を取得してください。

0件ならINSERTです。

◎質問者からの返答

なるほどこれは簡単ですね・・。なぜ思いつかなかったのでしょうか。

トランザクションが必要なければこの方法でいこうと思います。回答ありがとうございました!


3 ● ton-boo
●50ポイント ベストアンサー

既に他の回答にあるように、カラムにユニーク制約をつけてしまうのがこの場合最適のように私も思います。

その上で、何らかの事情で今からそういう変更をするのができないこともあるかもしれないので、「SELECT文とINSERT文を実行する間に、他のユーザにより先にINSERTされてしまうケースへの配慮が必要」という件について補足します。

トランザクションA トランザクションB
1 SELECT文でURLが存在しないことを確認⇒OK
2 SELECT文でURLが存在しないことを確認⇒OK(まだAによる行インサートが行われていないから)
3 列インサート
4 列インサート⇒チェックしたはずなのに、同じURLの行ができてしまう

※ 実際には1と2、3と4はどちらが先でも同じ話になります。

こういう事態を回避するために配慮が必要なわけですが、具体的には、トランザクション実行中には他のトランザクションがSELECTできないようにする必要があるわけです。

そのためには、RDBMSの種類によりますが、テーブルの排他ロックを取得したり、トランザクションの隔離レベルをシリアライザブルにしたり、という手順が必要となります。

いずれにしても、PHPの話というよりもRDBMSの話なので、これ以上の詳細については「どんなDBを使っているのか」という情報があったほうがよいかもしれません。


なお、テーブルロックは本当に必要な間だけ取得するようにしないと(シリアライザブルなトランザクションブロックはできるだけ短くしないと)、アクセス集中時に性能ボトルネックになりやすいことにも注意してください。

◎質問者からの返答

回答ありがとうございます。表のおかげでトランザクション処理の必要性が一目瞭然でした。


chuken_kenkouさんへのコメント欄で書いたのですが、今回自分が作るシステムに必要かどうかわからないのですが、勉強だと思って少し調べてみます。


丁寧にありがとうございました。勉強になりました!

関連質問


●質問をもっと探す●



0.人力検索はてなトップ
8.このページを友達に紹介
9.このページの先頭へ
対応機種一覧
お問い合わせ
ヘルプ/お知らせ
ログイン
無料ユーザー登録
はてなトップ