Обработка ошибок
Каждый сбой базы данных всплывает как единственный тип исключения —
CDOException, который всегда оборачивает исходный PDOException. Это означает
один catch на всю поверхность DML, с полными деталями SQLSTATE на расстоянии
одного getPrevious().
Исключение
Flytachi\Winter\Cdo\Connection\CDOException
└── extends \RuntimeExceptionCDOException — тонкий подкласс RuntimeException. Он несёт человекочитаемое
сообщение, описывающее операцию, а его $previous — это нижележащий
PDOException, сохраняющий код SQLSTATE, сообщение драйвера и трассировку стека.
Когда бросает каждый метод
| Ситуация | Метод |
|---|---|
| Сбой соединения PDO | CDO::__construct() |
Сбой INSERT |
insert(), insertGroup() |
Сбой UPDATE |
update() |
Сбой DELETE |
delete() |
| Сбой запроса апсерта | upsert(), upsertGroup() |
conflictColumns пуст |
upsert(), upsertGroup() |
in() / notIn() бросают другой тип
Передача пустого массива в Qb::in() / Qb::notIn() бросает
InvalidArgumentException (не CDOException) — это программная ошибка на этапе
построения, перехватываемая до запуска любого запроса. См.
Операторы Qb.
Перехват сбоев
Ловите CDOException, затем доставайте код из предыдущего PDOException:
use Flytachi\Winter\Cdo\Connection\CDOException;
try {
$cdo->insert('users', ['email' => 'alice@example.com', 'name' => 'Alice']);
} catch (CDOException $e) {
echo $e->getMessage(); // "Error when creating a record in the database (...)"
$pdo = $e->getPrevious(); // исходный PDOException
echo $pdo?->getCode(); // SQLSTATE, напр. "23505"
echo $pdo?->getMessage(); // сообщение драйвера
}Реакция на конкретную ошибку
Ветвитесь по коду SQLSTATE из обёрнутого исключения:
try {
$cdo->insert('users', $data);
} catch (CDOException $e) {
$pdo = $e->getPrevious();
// 23xxx = нарушение целостности (unique / FK) и на PG, и на MySQL
if ($pdo && str_starts_with((string) $pdo->getCode(), '23')) {
throw new DuplicateException('Already exists');
}
throw $e; // пробросить всё нераспознанное
}Справочник SQLSTATE
Частые коды, видимые через $e->getPrevious()->getCode():
| Код | Значение | База данных |
|---|---|---|
23000 |
Нарушение ограничения целостности | MySQL / MariaDB |
23505 |
Нарушение уникальности | PostgreSQL |
23503 |
Нарушение внешнего ключа | PostgreSQL |
42P01 |
Неопределённая таблица | PostgreSQL |
42000 |
Синтаксическая ошибка | MySQL / MariaDB |
08006 |
Сбой соединения | PostgreSQL |
HY000 |
Общая ошибка | Разные |
Шаблон «повтор при сбое»
При временной потере соединения переподключитесь один раз и повторите:
try {
$id = ConnectionPool::db(AppDb::class)->insert('events', $event);
} catch (CDOException $e) {
ConnectionPool::getConfigDb(AppDb::class)->reconnect();
$id = ConnectionPool::db(AppDb::class)->insert('events', $event);
}Связанное
- Логирование и диагностика — проверки здоровья и переподключения
- API CDO — что бросает каждый метод
- Операторы Qb — ошибки валидации на этапе построения