Файл TransactionTrait.php в Cotonti
Основное назначение файла TransactionTrait.php и его место в системе
Файл TransactionTrait.php в движке Cotonti CMF реализует трейд (помощник) для работы с транзакциями в базе данных. Его основное назначение — предоставить механизмы для управления транзакциями, включая начало транзакции, её коммит (подтверждение), откат (rollback), использование точек сохранения (savepoints) и обработку исключений, связанных с транзакциями.
Этот трейд используется в компонентах, которые работают с базой данных, и позволяет обеспечивать атомарность операций: транзакции гарантируют, что все изменения в базе данных либо будут применены, либо откатятся в случае ошибки. Это важно для предотвращения частичных изменений, которые могут нарушить целостность данных.
Трейд реализует основные функции для работы с транзакциями, включая управление уровнями изоляции транзакций, повторные попытки в случае ошибок параллелизма (например, deadlock), и обработку ошибок, связанных с потерей соединения с базой данных.
Основные задачи и условия, выполняемые кодом:
-
Управление транзакциями:
- Начало транзакции (
beginTransaction). - Коммит (подтверждение) транзакции (
commit). - Откат транзакции (
rollBack). - Использование точек сохранения (savepoints) для возможности отката к определенному состоянию в рамках одной транзакции.
- Начало транзакции (
-
Управление уровнями изоляции транзакций:
- Установка уровня изоляции транзакции (
setTransactionIsolationLevel).
- Установка уровня изоляции транзакции (
-
Повторные попытки транзакций в случае ошибок:
- Перехват и обработка ошибок, таких как deadlock или потеря соединения, с автоматической попыткой повторения транзакции при необходимости.
-
Обработка исключений:
- Обработка ошибок при выполнении транзакций и соответствующие меры для восстановления соединения или отката изменений.
Классы в файле:
- В файле
TransactionTrait.phpнет классов, так как это трейд, а не полноценный класс. Трейд используется другими классами для добавления функционала работы с транзакциями.
Методы и функции в файле:
-
transaction(Closure $callback, ?string $isolationLevel = null, int $attempts = 1):- Выполняет переданный в качестве аргумента callback в рамках транзакции.
- Позволяет задать уровень изоляции и количество попыток для транзакции в случае ошибок.
-
beginTransaction(?string $isolationLevel = null):- Начинает транзакцию и устанавливает уровень изоляции, если он был передан.
-
createTransaction(?string $isolationLevel = null):- Реализует логику начала транзакции, с проверкой на поддержку точек сохранения и уровня изоляции.
-
setTransactionIsolationLevel(string $isolationLevel):- Устанавливает уровень изоляции для транзакции, например,
READ COMMITTED,REPEATABLE READ, и т.д.
- Устанавливает уровень изоляции для транзакции, например,
-
supportsSavepoints(): bool:- Проверяет, поддерживает ли текущая СУБД (система управления базами данных) использование точек сохранения (savepoints).
-
commit():- Подтверждает изменения в базе данных, завершая транзакцию.
-
rollBack(?int $toLevel = null): void:- Откатывает транзакцию. Можно откатить до определенной точки сохранения, если она была установлена.
-
performRollBack(int $toLevel): void:- Реализует сам процесс отката транзакции, включая откат до конкретной точки сохранения, если это необходимо.
-
createSavepoint(string $name): void:- Создает точку сохранения в транзакции с заданным именем.
-
releaseSavepoint(string $name): void:- (Не реализовано для MySQL с PDO) Предназначено для освобождения точки сохранения.
-
rollBackSavepoint($name):- Откатывает изменения в транзакции до заданной точки сохранения.
-
handleBeginTransactionException(Throwable $e): void:- Обрабатывает исключения, возникающие при начале транзакции, например, восстановление соединения в случае его потери.
-
handleCommitTransactionException(Throwable $e, int $currentAttempt, int $maxAttempts): void:- Обрабатывает ошибки при коммите транзакции, например, deadlock или потеря соединения.
-
handleRollBackException(Throwable $e):- Обрабатывает ошибки при откате транзакции, например, при потере соединения.
-
handleTransactionException(Throwable $e, int $currentAttempt, int $maxAttempts):- Обрабатывает исключения при выполнении транзакционных операций, например, deadlock.
-
isConcurrencyError(Throwable $e): bool:- Проверяет, является ли ошибка ошибкой параллельности, такой как deadlock, на основе кода ошибки или сообщения.
Заключение:
Трейд TransactionTrait предоставляет мощный механизм для работы с транзакциями, включая поддержку уровней изоляции, точек сохранения и механизмы для повторения транзакций в случае ошибок. Этот функционал позволяет эффективно управлять транзакциями в различных сценариях, минимизируя риск потери данных и обеспечивая устойчивость приложения при параллельных запросах и сбоях соединения.
находится по адресу: /system/database/traits/TransactionTrait.php
<?php declare(strict_types=1); // Строгая типизация обязательна, что улучшает контроль типов в коде. namespace cot\database\traits; // Пространство имен для организации кода, относящегося к работе с базой данных. use Closure; // Подключение класса Closure для работы с анонимными функциями. use cot\database\exceptions\DeadlockException; // Подключение пользовательского исключения для обработки дедлоков в базе данных. use PDOException; // Подключение исключения PDO для обработки ошибок при работе с базой данных. use Throwable; // Подключение базового интерфейса для обработки всех исключений.
Этот фрагмент задает основу для работы с функциональностью транзакций в базе данных. Он подключает необходимые пространства имен и классы для обработки исключений и выполнения операций.
trait TransactionTrait
{
/**
* @var int
*/
protected $transactionLevel = 0; // Переменная для отслеживания текущего уровня вложенности транзакций.
Этот фрагмент кода определяет трейт TransactionTrait, который будет содержать методы для работы с транзакциями. Переменная $transactionLevel используется для хранения уровня вложенности транзакций, что важно для управления вложенными транзакциями в базе данных.
public function transaction(Closure $callback, ?string $isolationLevel = null, int $attempts = 1)
{
// Метод `transaction` выполняет переданный callback внутри транзакции.
// Он поддерживает повторные попытки в случае deadlock'ов.
// Параметры:
// - $callback: функция, которая выполняет действия в транзакции.
// - $isolationLevel: уровень изоляции транзакции (опционально).
// - $attempts: количество попыток выполнения транзакции.
for ($currentAttempt = 1; $currentAttempt <= $attempts; $currentAttempt++) {
// Цикл повторных попыток выполнения транзакции.
// $currentAttempt отслеживает текущую попытку.
// Выполняется до тех пор, пока не будут исчерпаны попытки.
$this->beginTransaction($isolationLevel);
// Начинает новую транзакцию с заданным уровнем изоляции ($isolationLevel).
try {
$result = $callback($this);
// Выполняет переданную функцию $callback, передавая текущий объект соединения.
} catch (Throwable $e) {
// Перехватывает любые ошибки или исключения, возникшие внутри транзакции.
$this->handleTransactionException($e, $currentAttempt, $attempts);
// Обрабатывает исключение (например, deadlock) и решает, нужно ли продолжать попытки.
continue;
// Если возникло исключение, продолжает цикл, переходя к следующей попытке.
}
try {
$this->commit();
// Пытается зафиксировать (commit) транзакцию, если выполнение прошло без ошибок.
} catch (Throwable $e) {
// Перехватывает любые ошибки или исключения, возникающие при фиксации транзакции.
$this->handleCommitTransactionException($e, $currentAttempt, $attempts);
// Обрабатывает исключение, связанное с commit'ом (например, ошибки БД).
continue;
// Если commit не удался, переходит к следующей попытке транзакции.
}
return $result;
// Если транзакция успешно завершена и зафиксирована, возвращает результат выполнения $callback.
}
return null;
// Возвращает null, если все попытки выполнения транзакции завершились неудачей.
}
Комментарии по коду:
- Назначение метода: Этот метод обрабатывает выполнение кода внутри транзакции. Он включает в себя обработку исключений, повторные попытки транзакции в случае deadlock'ов и управление уровнями изоляции.
- Уровень изоляции: Если уровень изоляции задан, он применяется перед началом транзакции.
- Обработка исключений: Если внутри транзакции возникает ошибка или deadlock, метод обрабатывает её и, при необходимости, повторяет попытку.
- Попытки транзакции: Параметр
$attemptsопределяет, сколько раз транзакция будет попытана до выброса исключения. - Результат: Если транзакция успешно завершена, возвращается результат выполнения
$callback. Если все попытки не удались, возвращаетсяnull.
/**
* Starts a transaction.
* @param ?string $isolationLevel The isolation level to use for this transaction.
*/
public function beginTransaction(?string $isolationLevel = null): void
{
$this->createTransaction($isolationLevel); // Создаётся новая транзакция с указанным уровнем изоляции (если задан).
$this->transactionLevel++; // Увеличивается уровень вложенности транзакций.
}
Объяснение:
-
$this->createTransaction($isolationLevel);
Метод создаёт новую транзакцию с уровнем изоляции, переданным в качестве параметра. Если уровень изоляции не указан, будет использоваться настройка по умолчанию. -
$this->transactionLevel++;
Счётчик уровней транзакции увеличивается. Это важно для отслеживания вложенных транзакций, чтобы не допустить ошибок при их вложении.
protected function createTransaction(?string $isolationLevel = null): void
{
if ($this->transactionLevel === 0) { // Если это первая транзакция (не вложенная)
if ($isolationLevel !== null) { // Если передан уровень изоляции
$this->setTransactionIsolationLevel($isolationLevel); // Устанавливаем уровень изоляции для транзакции.
}
try {
$this->adapter->beginTransaction(); // Начинаем новую транзакцию.
} catch (Throwable $e) { // Если возникла ошибка при начале транзакции
$this->handleBeginTransactionException($e); // Обрабатываем исключение при начале транзакции.
}
return; // Завершаем выполнение метода, так как транзакция началась.
}
if (!$this->supportsSavepoints()) { // Если не поддерживаются сохранённые точки
return; // Прерываем выполнение метода.
}
if ($this->adapter->inTransaction()) { // Если текущая сессия уже находится в транзакции
$this->createSavepoint('LEVEL_' . $this->transactionLevel); // Создаём сохранённую точку с уникальным названием для уровня транзакции.
}
}
Объяснение:
-
if ($this->transactionLevel === 0)
Этот блок проверяет, не является ли текущая транзакция первой. Если это так, то инициируется новая транзакция с возможностью задать уровень изоляции. -
$this->setTransactionIsolationLevel($isolationLevel);
Устанавливается уровень изоляции для текущей транзакции, если он был передан. -
$this->adapter->beginTransaction();
Метод начинает саму транзакцию через адаптер базы данных (например, через PDO). -
if (!$this->supportsSavepoints())
Если база данных не поддерживает сохранённые точки, то метод просто завершает выполнение, так как сохранённые точки не могут быть использованы. -
$this->adapter->inTransaction()
Проверка на то, находится ли текущая сессия уже в транзакции. Если да, то создаётся сохранённая точка для вложенной транзакции.
/**
* @param ?string $isolationLevel
*/
public function setTransactionIsolationLevel(string $isolationLevel): void
{
$this->query("SET TRANSACTION ISOLATION LEVEL $isolationLevel")->execute(); // Выполняем SQL-запрос для установки уровня изоляции транзакции.
}
Объяснение:
$this->query("SET TRANSACTION ISOLATION LEVEL $isolationLevel")->execute();
Этот метод формирует и выполняет SQL-запрос для установки уровня изоляции транзакции. Он использует параметр$isolationLevel, чтобы задать нужный уровень (например,READ COMMITTED,SERIALIZABLEи т.д.). Запрос будет отправлен в базу данных для изменения поведения транзакции.
public function supportsSavepoints(): bool
{
return true; // Метод всегда возвращает true, что означает, что поддержка сохранённых точек (savepoints) доступна.
}
Объяснение:
return true;
Этот метод всегда возвращаетtrue, что указывает на то, что система поддерживает сохранённые точки транзакций (savepoints). Это полезно для многоуровневых транзакций, когда необходимо откатить транзакцию до определённой точки, а не до начала транзакции.
public function commit()
{
$this->transactionLevel--; // Уменьшаем уровень вложенности транзакции.
if ($this->transactionLevel === 0) { // Если уровень транзакции вернулся к 0, значит это самая внешняя транзакция.
// ensure that the transaction wasn't autocommitted
if ($this->adapter->inTransaction()) { // Проверяем, находится ли текущая сессия в транзакции.
$this->adapter->commit(); // Подтверждаем транзакцию в базе данных.
}
return; // Завершаем метод, так как внешняя транзакция завершена.
}
// @todo is it really needed? // Комментарий, указывающий, что код ниже может быть не нужен.
// if ($this->supportsSavepoints()) { // Проверка на поддержку сохранённых точек транзакции.
// if ($this->adapter->inTransaction()) { // Проверка, в транзакции ли мы.
// $this->releaseSavepoint('LEVEL_' . $this->transactionLevel); // Освобождаем сохранённую точку для текущего уровня.
// }
// }
}
Объяснение:
-
$this->transactionLevel--;
Уменьшается уровень текущей транзакции. Это позволяет отслеживать, сколько уровней вложенности транзакций активны в данный момент. -
if ($this->transactionLevel === 0)
Если уровень транзакции достиг нуля, это означает, что транзакция больше не вложена в другую и является основной. -
if ($this->adapter->inTransaction())
Проверка, находится ли в данный момент система в активной транзакции. Это нужно для того, чтобы не попытаться завершить транзакцию, если она не была начата. -
$this->adapter->commit();
Подтверждение транзакции в базе данных. Это гарантирует, что все изменения, сделанные в рамках транзакции, будут сохранены. -
Закомментированный код о сохранённых точках:
Этот блок кода проверяет поддержку сохранённых точек и, если они поддерживаются, освобождает сохранённую точку на основе текущего уровня транзакции. Однако этот код закомментирован, и в комментарии отмечено, что возможно он не нужен.
/**
* Rolls back a transaction.
*/
public function rollBack(?int $toLevel = null): void
{
// Если уровень возврата не указан, то откатываем на предыдущий уровень транзакции.
$toLevel = $toLevel === null ? $this->transactionLevel - 1 : $toLevel;
// Если уровень возврата меньше 0 или больше текущего уровня, то откат невозможен.
if ($toLevel < 0 || $toLevel >= $this->transactionLevel) {
return; // Прерываем выполнение метода, так как условия для отката некорректны.
}
try {
$this->performRollBack($toLevel); // Попытка выполнить откат на указанный уровень транзакции.
} catch (Throwable $e) {
$this->handleRollBackException($e); // Обработка исключения, если откат не удался.
}
$this->transactionLevel = $toLevel; // Обновляем уровень транзакции после отката.
}
Объяснение:
-
$toLevel = $toLevel === null ? $this->transactionLevel - 1 : $toLevel;
Если параметр$toLevelне передан, то откатываемся на уровень, который был до текущего, то есть на предыдущий уровень транзакции. -
if ($toLevel < 0 || $toLevel >= $this->transactionLevel)
Проверка, чтобы убедиться, что указанный уровень отката корректен. Если уровень отката меньше нуля или больше текущего уровня транзакции, откат не будет выполнен. -
$this->performRollBack($toLevel);
Если уровень отката корректен, выполняем откат транзакции до указанного уровня. -
$this->handleRollBackException($e);
В случае ошибки при выполнении отката обрабатываем исключение. -
$this->transactionLevel = $toLevel;
После выполнения отката обновляем текущий уровень транзакции, чтобы он соответствовал уровню после отката.
protected function performRollBack(int $toLevel): void
{
// Если уровень отката равен 0, откатываем все транзакции до начального состояния.
if ($toLevel === 0) {
if ($this->adapter->inTransaction()) {
$this->adapter->rollBack(); // Откатываем всю транзакцию, если она активна.
}
return; // Прерываем выполнение метода, так как откат завершён.
}
// Если поддерживаются savepoints (точки сохранения), откатываем транзакцию до указанного уровня.
if ($this->supportsSavepoints()) {
if ($this->adapter->inTransaction()) {
$this->rollBackSavepoint('LEVEL_' . $toLevel); // Откатываем на указанный уровень savepoint.
}
}
}
Объяснение:
-
if ($toLevel === 0)
Если уровень отката равен 0, это означает, что нужно откатить всю транзакцию до начального состояния (нулевого уровня). В таком случае вызывается методrollBack()адаптера для отката всей транзакции. -
$this->adapter->inTransaction()
Проверяется, активна ли текущая транзакция, перед выполнением операции отката. -
$this->rollBackSavepoint('LEVEL_' . $toLevel);
Если поддерживаются точки сохранения (savepoints), откат происходит до определённого savepoint, заданного через уровень$toLevel. -
return;
После выполнения отката на уровень 0 выполнение метода завершается.
protected function createSavepoint(string $name): void
{
// Создаём точку сохранения с указанным именем.
$this->query("SAVEPOINT $name")->execute(); // Выполняем SQL-запрос для создания savepoint с заданным именем.
}
Объяснение:
$this->query("SAVEPOINT $name")->execute();
Здесь выполняется SQL-запрос, который создаёт точку сохранения в базе данных с именем, переданным в параметре$name. Это позволяет позже откатить транзакцию к этому состоянию, не отменяя всю транзакцию, если нужно.
protected function releaseSavepoint(string $name): void
{
// По какой-то причине это не работает в MySQL с PDO
//$this->query("RELEASE SAVEPOINT $name")->execute(); // Закомментированный код для выполнения SQL-запроса, который бы освобождал точку сохранения с указанным именем.
}
Объяснение:
- Закомментированный код:
- Комментарий указывает, что попытка выполнить команду
RELEASE SAVEPOINTс использованием PDO в MySQL не работает как ожидалось. - Строка кода, которая закомментирована, была бы использована для освобождения точки сохранения с именем, переданным в параметре
$name. - Это освобождение точки сохранения позволяет продолжить транзакцию после отката, исключая точку сохранения, к которой был выполнен откат.
- Комментарий указывает, что попытка выполнить команду
Таким образом, код явно не работает в текущей конфигурации, но был бы полезен для освобождения savepoint в другой базе данных, которая поддерживает эту команду.
public function rollBackSavepoint($name)
{
$this->query("ROLLBACK TO SAVEPOINT $name")->execute(); // Выполняет SQL-запрос, откатывая транзакцию до указанной точки сохранения с именем $name.
}
Объяснение:
- Метод
rollBackSavepoint: Этот метод выполняет откат транзакции до сохраненной точки (savepoint), указанной в параметре$name.- Запрос
ROLLBACK TO SAVEPOINT $nameоткатывает все изменения, сделанные после создания точки сохранения с именем$name, при этом сама точка сохранения остается доступной для дальнейшего использования в этой транзакции.
- Запрос
- Метод полезен, когда необходимо откатить только часть транзакции, не теряя всю информацию и возможность продолжить с того места, где была точка сохранения.
/**
* Обрабатывает исключение, возникшее при начале транзакции.
*/
protected function handleBeginTransactionException(Throwable $e): void
{
if ($this->isLostConnectionError($e)) { // Если ошибка связана с потерей соединения с базой данных
$this->reconnect(); // Попытка переподключения к базе данных
$this->adapter->beginTransaction(); // Повторно начинает транзакцию
return; // Завершаем выполнение метода, так как транзакция была успешно восстановлена
}
throw $e; // В случае другой ошибки, выбрасываем исключение снова
}
Объяснение:
- Метод
handleBeginTransactionException: Этот метод обрабатывает исключения, которые могут возникнуть при попытке начать транзакцию.- Если ошибка связана с потерей соединения (например, потеря связи с базой данных), вызывается метод
reconnect()для восстановления соединения с базой данных, и затем повторно инициируется начало транзакции с помощью$this->adapter->beginTransaction(). - Если ошибка не связана с потерей соединения, исключение пробрасывается дальше с помощью
throw $e.
- Если ошибка связана с потерей соединения (например, потеря связи с базой данных), вызывается метод
- Этот подход полезен, когда необходимо обеспечить восстановление транзакции после потери соединения, чтобы предотвратить сбои в процессе работы с базой данных.
protected function handleCommitTransactionException(Throwable $e, int $currentAttempt, int $maxAttempts): void
{
$this->transactionLevel = max(0, $this->transactionLevel - 1); // Уменьшаем уровень транзакции, но не ниже 0
if ($this->isConcurrencyError($e)) { // Если ошибка связана с конкуренцией (например, мертвая блокировка)
if ($currentAttempt < $maxAttempts) { // Если количество попыток меньше максимального
return; // Попробуем снова, не выбрасывая исключение
}
throw new DeadlockException($e->getMessage(), is_int($e->getCode()) ? $e->getCode() : 0, $e); // Иначе выбрасываем исключение DeadlockException
}
if ($this->isLostConnectionError($e)) { // Если ошибка связана с потерей соединения
$this->transactionLevel = 0; // Сбрасываем уровень транзакции
}
throw $e; // В любом другом случае выбрасываем исходное исключение
}
Объяснение:
-
Метод
handleCommitTransactionException: Этот метод обрабатывает исключения, возникающие при попытке зафиксировать транзакцию (commit).- Если ошибка является ошибкой конкуренции (например, мертвая блокировка), и количество текущих попыток меньше максимального, транзакция не отменяется, а выполняется повторная попытка.
- Если количество попыток превышает максимальное, выбрасывается исключение
DeadlockException. - Если ошибка связана с потерей соединения, уровень транзакции сбрасывается в 0.
- В любом другом случае выбрасывается исходное исключение, переданное в метод.
-
Этот подход позволяет гибко обрабатывать ошибки транзакций, такие как конкуренция и проблемы с соединением, и при необходимости повторять транзакцию или выбрасывать исключение после нескольких попыток.
protected function handleRollBackException(Throwable $e)
{
if ($this->isLostConnectionError($e)) { // Если ошибка связана с потерей соединения
$this->transactionLevel = 0; // Сбрасываем уровень транзакции в 0
}
throw $e; // В любом другом случае выбрасываем исходное исключение
}
Объяснение:
-
Метод
handleRollBackException: Этот метод обрабатывает исключения, возникающие при откате транзакции (rollback).- Если ошибка связана с потерей соединения, уровень транзакции сбрасывается в 0, чтобы избежать дальнейших проблем с транзакциями.
- В любом другом случае выбрасывается исходное исключение, переданное в метод.
-
Этот подход позволяет эффективно управлять состоянием транзакций при возникновении ошибок, таких как потеря соединения, и обрабатывать их корректно, сбрасывая уровень транзакции, чтобы предотвратить дальнейшие сбои.
/**
* Handle an exception encountered when running a transacted statement.
*/
protected function handleTransactionException(Throwable $e, int $currentAttempt, int $maxAttempts)
{
// При мертвой блокировке (deadlock), MySQL откатывает всю транзакцию, поэтому мы не можем просто
// повторить запрос. Нам нужно выбросить это исключение наружу и
// позволить разработчику обработать это другим способом. Также мы уменьшаем уровень транзакции.
if ($this->isConcurrencyError($e)) { // Проверка на ошибку параллельности (deadlock)
if ($this->transactionLevel > 1) { // Если уровень транзакции больше 1
$this->transactionLevel--; // Уменьшаем уровень транзакции
throw new DeadlockException($e->getMessage(), is_int($e->getCode()) ? $e->getCode() : 0, $e); // Генерируем исключение DeadlockException
}
$this->rollBack(); // Откатываем транзакцию, если уровень транзакции 1
if ($currentAttempt < $maxAttempts) { // Если попыток еще осталось
return; // Повторяем попытку выполнения транзакции
}
}
throw $e; // Если ошибка не связана с deadlock, выбрасываем исходное исключение
}
Объяснение:
-
Метод
handleTransactionException: Этот метод обрабатывает исключения, возникшие при выполнении транзакции.- Deadlock (мертвая блокировка): Если ошибка связана с deadlock (конкуренцией), то при нескольких уровнях транзакции, уровень уменьшается, и выбрасывается исключение
DeadlockException. - Если попытки повторить транзакцию превышены, то она откатывается, и происходит выброс исходного исключения.
- Важно, что при ошибке параллельности (например, deadlock) метод позволяет повторить транзакцию, если число попыток еще не исчерпано.
- Если же ошибка не связана с deadlock, просто выбрасывается исходное исключение.
- Deadlock (мертвая блокировка): Если ошибка связана с deadlock (конкуренцией), то при нескольких уровнях транзакции, уровень уменьшается, и выбрасывается исключение
-
Это помогает эффективно обрабатывать ситуацию с deadlock, предлагая возможность повторить транзакцию в случае ошибок параллельности.
protected function isConcurrencyError(Throwable $e): bool
{
// Проверка, является ли ошибка ошибкой параллельности (например, deadlock)
if ($e instanceof PDOException && ($e->getCode() === 40001 || $e->getCode() === '40001')) { // Если ошибка PDO с кодом 40001
return true; // Ошибка параллельности (deadlock)
}
// Список ключевых фраз, которые могут указывать на deadlock
$needles = [
'Deadlock found when trying to get lock', // Сообщение о deadlock при попытке заблокировать ресурс
'deadlock detected', // Сообщение о детектированном deadlock
'The database file is locked', // База данных заблокирована
'database is locked', // База данных заблокирована
'database table is locked', // Таблица базы данных заблокирована
'A table in the database is locked', // Таблица в базе данных заблокирована
'has been chosen as the deadlock victim', // Было выбрано как жертва deadlock
'Lock wait timeout exceeded; try restarting transaction', // Превышен тайм-аут ожидания блокировки, попробуйте перезапустить транзакцию
'WSREP detected deadlock/conflict and aborted the transaction. Try restarting the transaction', // Сообщение о deadlock с использованием WSREP
];
$haystack = mb_strtolower($e->getMessage()); // Приводим сообщение об ошибке к нижнему регистру для поиска
// Проверка, содержит ли сообщение об ошибке одну из ключевых фраз
foreach ($needles as $needle) { // Перебираем все ключевые фразы
if (mb_stripos($haystack, $needle) !== null) { // Если фраза найдена в сообщении об ошибке
return true; // Это ошибка параллельности
}
}
return false; // Если ни одна из фраз не найдена, то это не ошибка параллельности
}
Объяснение:
-
Метод
isConcurrencyError: Этот метод проверяет, является ли ошибка ошибкой параллельности (например, deadlock).- Сначала проверяется, является ли ошибка
PDOExceptionс кодом ошибки40001, который часто указывает на deadlock. - Затем метод проверяет сообщение об ошибке на наличие ключевых фраз, таких как "Deadlock found when trying to get lock", "database is locked" и других, которые могут свидетельствовать о проблемах с блокировкой базы данных или deadlock.
- Если хотя бы одна из ключевых фраз найдена в сообщении, метод возвращает
true, указывая, что ошибка связана с deadlock. - Если фраз не найдено, возвращается
false.
- Сначала проверяется, является ли ошибка
-
Этот метод важен для обработки транзакционных ошибок, связанных с блокировками, и позволяет принять решение о повторении транзакции при deadlock.
Комментарии (0)
Автор контента
Оффлайн
Administrator
Последняя авторизация: 05.07.2026 18:32
- Страница размещена: 28.01.2025 02:05
- Последнее обновление: 28.01.2025 02:57