#php #mysql #laravel #eloquent
#php #mysql #laravel #красноречивый
Вопрос:
У меня есть эта простая функция, и я хочу выполнить транзакцию laravel. Он вставляет первый (вторичный ресурс), в то время как второй (основной ресурс) содержит ошибку, и я хочу выполнить откат и удалить вторичный ресурс, как только произошла ошибка.
try {
DB::transaction(function () use ($request) {
$Share = new SecondaryShares();
$Share->secondary_name = $request->secondaryName;
$Share->primary_id = $request->primaryId
$Share->save();
//error in primaryname==> correct is primary_name
$Share = new PrimaryShares();
$Share->primaryname = $request->primaryName;
$Share->percentage = $request->percentage;
$Share->visibility = $visibility;
$Share->save();
});
} catch (Exception $e) {
dd('failed');
}
dd('worked');
Как я могу это исправить?
Заранее спасибо.
Комментарии:
1. Можете ли вы подробнее объяснить, что не работает с данным кодом?
2. вы уверены, что код в блоке catch выполнен? Также, что делает этот код? Некоторые инструкции неявно фиксируются в MySQL, и откат также может быть невозможен .
3. У меня есть две таблицы, первичная и вторичная. Я поместил преднамеренную ошибку в основной общий ресурс. Прежде всего, он вставит вторичный общий ресурс, а затем перейдет через код к основному. Как только ошибка возникнет, я хочу удалить вставленный дополнительный ресурс до
4. я советую вам предоставить table structures (
SHOW CREATE TABLE table
) для обеих таблиц и опубликовать SQL-код, который генерируется на основе этого кода..
Ответ №1:
Вы неправильно используете систему транзакций. Существует два способа его использования, и вы смешиваете их, хотя этого никогда не следует делать.
Вариант 1: Закрытие транзакции
Вы можете поместить свой код в закрытие транзакции. Как только генерируется Exception
(фактически Throwable
) или любой тип исключения, наследуемый от этих типов, транзакция будет откатана, и исключение будет повторно сгенерировано обработчиком закрытия:
DB::transaction(function () {
$model1 = MyModel::create();
// model2 will not be created if model1 couldn't be created
$model2 = MyModel::create();
});
Вы также можете завершить закрытие транзакции с помощью try-catch, чтобы перехватить любое исключение транзакции:
try {
DB::transaction(function () {
$model1 = MyModel::create();
// model2 will not be created if model1 couldn't be created
$model2 = MyModel::create();
});
} catch (Exception $e) {
Log::error('Insert failed', ['exception' => $e]);
return redirect()->back()->withInput();
}
return redirect()->route('form.success');
Вариант 2: Управление транзакциями
Или, в качестве альтернативы, вы можете управлять логикой транзакции самостоятельно. Но будьте осторожны, этот способ более опасен, потому что довольно легко забывается откат или фиксация:
DB::beginTransaction();
$model1 = MyModel::create();
if ($model1->exists !== true) {
DB::rollBack();
Log::error('Insert 1 failed');
return redirect()->back()->withInput();
}
$model2 = MyModel::create();
if ($model2->exists !== true) {
DB::rollBack();
Log::error('Insert 2 failed');
return redirect()->back()->withInput();
}
DB::commit();
return redirect()->route('form.success');
На мой взгляд, использование варианта 2 дает намного больше кода и менее читабельно.
Кстати, Laravel использует пользовательские исключения базы данных. Он выдает a IlluminateDatabaseQueryException
и no PDOException
.
Комментарии:
1. «На мой взгляд, использование варианта 2 дает намного больше кода и менее читаемо». По моему мнению, вариант 2 может быть более понятным: вы открываете транзакцию, а затем модель не существует, вы собираетесь выполнить откат, если все в порядке, выполните фиксацию, первый вариант более подробный, потому что вы не знаете, что происходит под капотом, не раскрывая это в документации.. Возможно, следует вызвать функцию
DB::transactionAutoCommitOnSuccessAndRollbackOnException
, тогда вы знаете, что происходит, когда вы читаете имя функции2. она выдается в catch, даже если исключение pdo. вариант 1: то же, что я использую вариант 2: не удаляет model1, если model2 выдает ошибку
3. вы уверены, что используете InnoDB как механизм обработки таблиц? @ahmad, вот почему я попросил тебя создать структуры таблиц.
4. Это вызвано тем, что вы перехватили неправильное исключение. Но это не имеет значения, потому что закрытие в любом случае приведет к откату транзакции. По крайней мере, до тех пор, пока вы не вмешиваетесь вручную с
DB::rollBack()
.5. @RaymondNijland Код и логика
DB::transaction($closure)
чрезвычайно прямолинейны. Да, Laravel абстрагирует большую часть реальной транзакционной логики, предоставляя это закрытие, но это не значит, что это плохо. Исходя из моего опыта, я могу сказать вам, что при работе с вариантом 2 у нас было больше ошибок, чем с вариантом 1. И в документации к варианту 1 четко указано, как это работает — нет необходимости в преувеличенном имени метода.
Ответ №2:
Моя база данных — InnoDB, но я выяснил, что таблицы — это MyISAM. решаемая путем добавления этой строки кода в миграцию: $table-> engine = «InnoDB»;