I have a MySQL table which has a field for email addresses which is defined as unique. For this example, let\'s say that all my form does is allow a user to insert their em
Be aware that if you have an AUTO_INCREMENT column and you are using InnoDB, then a failed INSERT does increment the "next auto-id" value, despite no new row being added. See for example the documentation for INSERT ... ON DUPLICATE KEY and AUTO_INCREMENT Handling in InnoDB. This leads to gaps in AUTO_INCREMENT ids, which may be a concern if you think you might run out of ids.
So if you expect that attempting to insert an already existing row is common, and you want to avoid gaps in AUTO_INCREMENT ids as much as possible, you can do both pre-emptive checking and exception handling:
$already_exists = false;
$stmt = $pdo->prepare("SELECT id FROM emails WHERE email = :email");
$stmt->execute(array(':email' => $email));
if ($stmt->rowCount() > 0) {
$already_exists = true;
}
else {
try {
$stmt = $pdo->prepare("INSERT INTO emails (email) VALUES (:email)");
$stmt->execute(array(':email' => $email));
} catch (PDOException $e) {
if ($e->errorInfo[1] == 1062) {
$already_exists = true;
} else {
throw $e;
}
}
}
The first query ensures that we do not attempt to insert the email if we know for sure that it already exists. The second query attempts to insert the email if it seems not to exist yet. We still need to check for exceptions in the second query since a duplicate may still occur in the unlikely case of a race condition (multiple clients or threads running the snippet above in parallel).
This approach makes the code robust, while still avoiding to create gaps in AUTO_INCREMENT ids except in the rare case of race conditions. It is also the fastest approach if attempting to insert an existing email is more common than attempting to insert an new email. If attempting to insert an existing email is rare, and you don't care about gaps in AUTO_INCREMENT ids, then there is no need for the pre-emptive check.