Laravel: Использование try... catch с DB:: transaction()
Мы используем DB::transaction()
для нескольких запросов на вставку. При этом, если try...catch
должен быть помещен внутрь или обернуть его? Нужно ли включать try...catch
, когда транзакция автоматически завершится ошибкой, если что-то пойдет не так?
Пример try...catch
завершение транзакции:
// try...catch
try {
// Transaction
$exception = DB::transaction(function() {
// Do your SQL here
});
if(is_null($exception)) {
return true;
} else {
throw new Exception;
}
}
catch(Exception $e) {
return false;
}
Противоположность, DB::transaction()
упаковка try... catch:
// Transaction
$exception = DB::transaction(function() {
// try...catch
try {
// Do your SQL here
}
catch(Exception $e) {
return $e;
}
});
return is_null($exception) ? true : false;
Или просто транзакция без попытки... catch
// Transaction only
$exception = DB::transaction(function() {
// Do your SQL here
});
return is_null($exception) ? true : false;
Ответы
Ответ 1
В случае, если вам нужно вручную "вывести" транзакцию через код (будь то через исключение или просто проверить состояние ошибки), вы не должны использовать DB::transaction()
, а вместо этого сверните свой код в DB::beginTransaction
и DB::commit
/DB::rollback()
:
DB::beginTransaction();
try {
DB::insert(...);
DB::insert(...);
DB::insert(...);
DB::commit();
// all good
} catch (\Exception $e) {
DB::rollback();
// something went wrong
}
См. документы о транзакциях.
Ответ 2
Если вы используете PHP7, используйте Throwable в catch
для обнаружения пользовательских исключений и фатальных ошибок.
Например:
DB::beginTransaction();
try {
DB::insert(...);
DB::commit();
} catch (\Throwable $e) {
DB::rollback();
throw $e;
}
Если ваш код должен быть совместимым с PHP5, используйте Exception
и Throwable
:
DB::beginTransaction();
try {
DB::insert(...);
DB::commit();
} catch (\Exception $e) {
DB::rollback();
throw $e;
} catch (\Throwable $e) {
DB::rollback();
throw $e;
}
Ответ 3
Вы можете обернуть транзакцию через try..catch или даже отменить их,
здесь мой пример кода, который я использовал в laravel 5, если вы посмотрите внутри DB:transaction()
в Illuminate\Database\Connection
, что то же самое, что вы пишете ручную транзакцию,
Транзакция Laravel
public function transaction(Closure $callback)
{
$this->beginTransaction();
try {
$result = $callback($this);
$this->commit();
}
catch (Exception $e) {
$this->rollBack();
throw $e;
} catch (Throwable $e) {
$this->rollBack();
throw $e;
}
return $result;
}
чтобы вы могли написать свой код, как это, и обработать свое исключение, например, отправить сообщение в форму через флеш или перенаправить на другую страницу. Возвращаемое возвратное внутреннее закрытие возвращается в транзакции(), поэтому, если вы вернетесь redirect()->back()
, он не будет перенаправлен немедленно, потому что он возвращается в переменной, которая обрабатывает транзакцию.
транзакция Wrap
$result = DB::transaction(function () use ($request, $message) {
try{
// execute query 1
// execute query 2
// ..
return redirect(route('account.article'));
} catch (\Exception $e) {
return redirect()->back()
->withErrors(['error' => $e->getMessage());
}
});
// redirect the page
return $result;
тогда альтернативой является булева логическая переменная и переадресация дескриптора внешней транзакции или если вам нужно восстановить причину неудачной транзакции, вы можете получить ее от $e->getMessage()
внутри catch(Exception $e){...}