アップデート
2 つの一意のフィールドがあり、どちらも null にすることを許可したくない場合 (1 つのテーブルを "null 可能" に設定し、2 つのクエリを実行できることがわかっているため)、どちらが台無しになっているかを確認する方法はありますか? ユーザー名または電子メールが取得されたかどうかをユーザーに知らせたいのと同じように。単一の挿入を行うと、どれが失敗したかわかりません
さらに、ステートメントが 2 つある場合 (最初にユーザー名を挿入し、失敗したかどうかを確認し、次に電子メールで同じことを試す)、一度に 1 つのエラーしか検出できません。ユーザー名が失敗してロールバックした場合、メールに対して同じことを試みることはできません(メールが存在する場合でも、最初のクエリが失敗したかどうかを確認する必要があるため、冗長になります)編集:できると思いますネストされた try...catch ステートメントを使用すると機能します
私はあなたがこれを考えすぎていると思います。ユーザーごとに異なるエラーを表示できますが、実際には一度に 1 つしか検出できません。前のクエリを仮定すると (すべての値を一度に挿入するため):
try {
$stmt = $db->prepare($sql);
$stmt->execute(array(
':username' => $username,
':email' => $email,
':password' => $password
));
$db->commit();
} catch (PDOException $e) {
$db->rollBack();
if($e->getCode() == 23000) {
// lets parse the message
if(false !== strpos('email', $e->getMessage())) {
echo 'Email "'. $email . '" already exists';
} else if(false !== strpos('username', $e->getMessage()) {
echo 'Username "'. $username .'" taken';
}
} else {
// not a dupe key rethrow error
throw $e;
}
}
エラーメッセージは次のようになります。
Duplicate entry 'THE_VALUE_YOU_TRIED_TO_INSERT' for key THE_KEY_NAME
どの列であったかについてより意味のあるレポートを取得する方法は、テーブルを作成するときに意味のある名前を付けてインデックスに名前を付けることです。たとえば、次のようにします。
CREATE TABLE the_table (
`id` integer UNSIGNED NOT NULL AUTO_INCREMENT
`username` varchar(30),
`email` varchar(100),
`password` varchar(32),
PRIMARY KEY (`id`),
UNIQUE KEY `uk_email` (`email`),
UNIQUE KEY `uk_username` (`username`)
);
エラーメッセージは次のようになります。
Duplicate entry 'THE_VALUE_YOU_TRIED_TO_INSERT' for key uk_username
また
Duplicate entry 'THE_VALUE_YOU_TRIED_TO_INSERT' for key uk_email
これは簡単に解析できます。
この方法に代わる唯一の実際の方法は、挿入する前にテーブルで選択を実行して、値がまだ存在しないことを確認することです。
PDO を使用している場合、PHP の警告は表示されません... 例外のみで、キャッチされない場合は標準の php エラーが生成されます。display_errors
オフにした場合、画面には出力されず、エラーログにのみ出力されます。
insert if not exists
一意のキーを使用してから例外をキャッチする方法があるとは思わない:
$db = new PDO($dsn, $user, $pass);
$sql = "INSERT INTO the_table (username, email, etc) VALUES (:username,:email,:password)";
$db->beginTransaction();
try {
$stmt = $db->prepare($sql);
$stmt->execute(array(
':username' => $username,
':email' => $email,
':password' => $password
));
$db->commit();
} catch (PDOException $e) {
$db->rollBack();
if($e->getCode() == 23000) {
// do something to notify username is taken
} else {
// not a dupe key rethrow error
throw $e;
}
}