Wszyscy używamy DB::transaction()
do wielu zapytań wstawiania. Czy robiąc to, należy try...catch
umieścić w środku, czy owinąć? Czy w ogóle konieczne jest uwzględnienie, try...catch
kiedy transakcja automatycznie się nie powiedzie, jeśli coś pójdzie nie tak?
Przykładowe try...catch
opakowanie transakcji:
// 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;
}
Wręcz przeciwnie, DB::transaction()
zawijanie próba ... haczyka:
// Transaction
$exception = DB::transaction(function() {
// try...catch
try {
// Do your SQL here
}
catch(Exception $e) {
return $e;
}
});
return is_null($exception) ? true : false;
Lub po prostu transakcja bez próby ... złapania
// Transaction only
$exception = DB::transaction(function() {
// Do your SQL here
});
return is_null($exception) ? true : false;
php
laravel
transactions
urok
źródło
źródło
\Exception
? Czy mogę to uchwycić tym generycznym\Exception
? Świetnie, jeśli to jest!DB::beginTransaction()
iDB:transaction()
?Jeśli używasz PHP7, użyj Throwable in
catch
do wychwytywania wyjątków użytkowników i błędów krytycznych.Na przykład:
DB::beginTransaction(); try { DB::insert(...); DB::commit(); } catch (\Throwable $e) { DB::rollback(); throw $e; }
Jeśli Twój kod musi być porównywalny z PHP5, użyj
Exception
iThrowable
:DB::beginTransaction(); try { DB::insert(...); DB::commit(); } catch (\Exception $e) { DB::rollback(); throw $e; } catch (\Throwable $e) { DB::rollback(); throw $e; }
źródło
catch
bloku. Dlatego dobre miejsceDB::beginTransaction()
jest przedtry
blokiem.Można owijania transakcję ponad try..catch lub nawet je odwrócić, oto mój przykładowy kod użyłem w laravel 5 ,, jeśli spojrzeć głęboko wewnątrz
DB:transaction()
wIlluminate\Database\Connection
które tak samo jak piszesz ręczną transakcję.Laravel Transaction
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; }
więc możesz napisać swój kod w ten sposób i obsłużyć wyjątek, na przykład wrzucić wiadomość z powrotem do formularza przez flash lub przekierować na inną stronę. PAMIĘTAJ, że zwrot wewnątrz zamknięcia jest zwracany w transakcji (), więc jeśli wrócisz
redirect()->back()
, nie przekieruje od razu, ponieważ wróciło do zmiennej obsługującej transakcję.Zawiń transakcję
$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;
wtedy alternatywą jest rzucanie zmiennej boolowskiej i obsługa przekierowania na zewnątrz funkcji transakcji lub jeśli potrzebujesz dowiedzieć się, dlaczego transakcja się nie powiodła, możesz to uzyskać od
$e->getMessage()
wewnątrzcatch(Exception $e){...}
źródło
Postanowiłem udzielić odpowiedzi na to pytanie, ponieważ myślę, że można to rozwiązać za pomocą prostszej składni niż zawiły blok try-catch. Dokumentacja Laravel jest dość krótka na ten temat.
Zamiast używać try-catch, możesz po prostu użyć
DB::transaction(){...}
opakowania w następujący sposób:// 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!']); }); };
Powinieneś wtedy zobaczyć, że rekord użytkownika i dziennika nie mogą istnieć bez siebie.
Kilka uwag na temat powyższej implementacji:
return
że dokonałeś transakcji, abyś mógł użyćresponse()
zwrotu w ramach jej callback.throw
istnieje wyjątek, jeśli chcesz, aby transakcja została wycofana (lub mieć zagnieżdżoną funkcję, która automatycznie zgłasza wyjątek, jak wyjątek SQL z poziomu Eloquent).id
,updated_at
,created_at
Oraz wszelkie inne pola są dostępne po utworzeniu dla$user
obiektu (na czas trwania tej transakcji). Transakcja zostanie przeprowadzona według dowolnej logiki tworzenia, którą posiadasz. JEDNAK, cały rekord jest odrzucany, gdyAnyException
jest rzucany. Oznacza to, że na przykład kolumna automatycznego zwiększania wartościid
jest zwiększana w przypadku nieudanych transakcji.Testowane na Laravel 5.8
źródło