# PDOException: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'john@example.com' for key 'users_email_unique'

- **ID:** `php/pdo-sqlstate-23000-duplicate-entry-unique-constraint`
- **Domain:** php
- **Category:** data_error
- **Error Code:** `1062`
- **Verification:** ai_generated
- **Fix Rate:** 85%

## Root Cause

An INSERT or UPDATE operation attempted to create a duplicate value in a column that has a UNIQUE constraint, usually due to race conditions, missing checks, or concurrent requests.

## Version Compatibility

| Version | Status | Introduced | Deprecated |
|---------|--------|------------|------------|
| MySQL 8.0.34 | active | — | — |
| MariaDB 10.11.0 | active | — | — |
| PHP 8.2.0 | active | — | — |

## Workarounds

1. **Use INSERT IGNORE or ON DUPLICATE KEY UPDATE to handle duplicates gracefully:
$stmt = $pdo->prepare('INSERT INTO users (email, name) VALUES (:email, :name) ON DUPLICATE KEY UPDATE name = VALUES(name)');
$stmt->execute([':email' => 'john@example.com', ':name' => 'John']);** (95% success)
   ```
   Use INSERT IGNORE or ON DUPLICATE KEY UPDATE to handle duplicates gracefully:
$stmt = $pdo->prepare('INSERT INTO users (email, name) VALUES (:email, :name) ON DUPLICATE KEY UPDATE name = VALUES(name)');
$stmt->execute([':email' => 'john@example.com', ':name' => 'John']);
   ```
2. **Implement a retry mechanism with a short delay if the exception occurs:
try { $stmt->execute(); } catch (PDOException $e) { if ($e->errorInfo[1] == 1062) { usleep(100000); $stmt->execute(); } else { throw $e; } }** (80% success)
   ```
   Implement a retry mechanism with a short delay if the exception occurs:
try { $stmt->execute(); } catch (PDOException $e) { if ($e->errorInfo[1] == 1062) { usleep(100000); $stmt->execute(); } else { throw $e; } }
   ```

## Dead Ends

- **Removing the UNIQUE constraint on the column to allow duplicates** — This violates data integrity and can lead to application logic bugs; not a real fix but a workaround that breaks the schema. (95% fail)
- **Wrapping every INSERT in a SELECT to check existence first without using transactions** — Race conditions still occur between SELECT and INSERT in concurrent environments; does not solve the problem reliably. (80% fail)
