Wir alle verwenden DB::transaction()
für mehrere Einfügeabfragen. Sollte dabei ein Platz try...catch
darin platziert oder eingewickelt werden? Ist es überhaupt notwendig anzugeben, try...catch
wann eine Transaktion automatisch fehlschlägt, wenn etwas schief geht?
Beispiel für das try...catch
Umschließen einer Transaktion:
// 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;
}
Im Gegenteil, DB::transaction()
ein Versuch einpacken ... fangen:
// Transaction
$exception = DB::transaction(function() {
// try...catch
try {
// Do your SQL here
}
catch(Exception $e) {
return $e;
}
});
return is_null($exception) ? true : false;
Oder einfach eine Transaktion ohne zu versuchen ... zu fangen
// Transaction only
$exception = DB::transaction(function() {
// Do your SQL here
});
return is_null($exception) ? true : false;
quelle
\Exception
? Kann ich es mit diesem Generikum erfassen\Exception
? Großartig, wenn es so ist!DB::beginTransaction()
undDB:transaction()
?Wenn Sie PHP7 verwenden, verwenden Sie Throwable in,
catch
um Benutzerausnahmen und schwerwiegende Fehler abzufangen .Zum Beispiel:
DB::beginTransaction(); try { DB::insert(...); DB::commit(); } catch (\Throwable $e) { DB::rollback(); throw $e; }
Wenn Ihr Code mit PHP5 kompatibel sein muss, verwenden Sie
Exception
undThrowable
:DB::beginTransaction(); try { DB::insert(...); DB::commit(); } catch (\Exception $e) { DB::rollback(); throw $e; } catch (\Throwable $e) { DB::rollback(); throw $e; }
quelle
catch
Block zu versuchen . Daher ist ein guter PlatzDB::beginTransaction()
vor demtry
Block.Sie könnten die Transaktion um try..catch wickeln oder sogar umkehren, hier mein Beispielcode, den ich in Laravel 5 verwendet habe, wenn Sie genau so tief
DB:transaction()
inIlluminate\Database\Connection
das Innere schauen , wie Sie eine manuelle Transaktion schreiben.Laravel-Transaktion
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; }
So können Sie Ihren Code so schreiben und Ihre Ausnahme so behandeln, als würden Sie eine Nachricht per Flash zurück in Ihr Formular werfen oder auf eine andere Seite umleiten. Denken Sie daran, dass die Rückgabe innerhalb des Abschlusses in transaction () zurückgegeben wird. Wenn Sie
redirect()->back()
sie zurückgeben, wird sie nicht sofort umgeleitet, da sie an die Variable zurückgegeben wird, die die Transaktion verarbeitet.Wrap-Transaktion
$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;
Dann besteht die Alternative darin, eine boolesche Variable zu werfen und die Umleitung außerhalb der Transaktionsfunktion durchzuführen. Wenn Sie herausfinden möchten, warum die Transaktion fehlgeschlagen ist, können Sie sie von
$e->getMessage()
innen abrufencatch(Exception $e){...}
quelle
Ich habe beschlossen, eine Antwort auf diese Frage zu geben, da ich denke, dass sie mit einer einfacheren Syntax als dem verschlungenen Try-Catch-Block gelöst werden kann. Die Laravel-Dokumentation ist zu diesem Thema ziemlich kurz.
Anstatt try-catch zu verwenden, können Sie den
DB::transaction(){...}
Wrapper einfach wie folgt verwenden:// MyController.php public function store(Request $request) { return DB::transaction(function() use ($request) { $user = User::create([ 'username' => $request->post('username') ]); // Add some sort of "log" record for the sake of transaction: $log = Log::create([ 'message' => 'User Foobar created' ]); // Lets add some custom validation that will prohibit the transaction: if($user->id > 1) { throw AnyException('Please rollback this transaction'); } return response()->json(['message' => 'User saved!']); }); };
Sie sollten dann sehen, dass der Benutzer und der Protokolldatensatz nicht ohne einander existieren können.
Einige Hinweise zur Implementierung oben:
return
die Transaktion sicher , damit Sie dieresponse()
Rückgabe innerhalb des Rückrufs verwenden können.throw
eine Ausnahme sicher, wenn Sie möchten, dass die Transaktion zurückgesetzt wird (oder wenn Sie eine verschachtelte Funktion haben, die die Ausnahme automatisch für Sie auslöst, wie eine SQL-Ausnahme aus Eloquent).id
,updated_at
,created_at
und alle anderen Felder sind verfügbar , nachdem CREATION für das$user
Objekt (für die Dauer der Transaktion). Die Transaktion durchläuft eine beliebige Erstellungslogik. JEDOCH wird der gesamte Datensatz verworfen, wenn derAnyException
geworfen wird. Dies bedeutet, dass beispielsweise eine Spalte fürid
die automatische Inkrementierung für fehlgeschlagene Transaktionen inkrementiert wird.Getestet auf Laravel 5.8
quelle