Todos usamos DB::transaction()
para múltiples consultas de inserción. Al hacerlo, ¿se try...catch
debe colocar una dentro o envolverla? ¿Es incluso necesario incluir un try...catch
cuándo una transacción fallará automáticamente si algo sale mal?
Ejemplo de try...catch
envoltura de una transacción:
// 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;
}
Todo lo contrario, DB::transaction()
envolver un intento ... captura:
// Transaction
$exception = DB::transaction(function() {
// try...catch
try {
// Do your SQL here
}
catch(Exception $e) {
return $e;
}
});
return is_null($exception) ? true : false;
O simplemente una transacción sin intentar ... atrapar
// Transaction only
$exception = DB::transaction(function() {
// Do your SQL here
});
return is_null($exception) ? true : false;
php
laravel
transactions
mejorar
fuente
fuente
\Exception
? ¿Puedo capturarlo con este genérico\Exception
? ¡Genial si lo es!DB::beginTransaction()
yDB:transaction()
?Si usa PHP7, use Throwable in
catch
para detectar excepciones de usuario y errores fatales.Por ejemplo:
DB::beginTransaction(); try { DB::insert(...); DB::commit(); } catch (\Throwable $e) { DB::rollback(); throw $e; }
Si su código debe ser compartible con PHP5, use
Exception
yThrowable
:DB::beginTransaction(); try { DB::insert(...); DB::commit(); } catch (\Exception $e) { DB::rollback(); throw $e; } catch (\Throwable $e) { DB::rollback(); throw $e; }
fuente
catch
bloque. Por lo tanto, un buen lugarDB::beginTransaction()
es antes deltry
bloque.Puede envolver la transacción sobre try..catch o incluso revertirlos, aquí mi código de ejemplo que solía usar en laravel 5, si mira profundamente
DB:transaction()
enIlluminate\Database\Connection
eso, es lo mismo que escribe una transacción manual.Transacción 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; }
para que pueda escribir su código de esta manera y manejar su excepción, como devolver un mensaje a su formulario a través de flash o redirigir a otra página. RECUERDE el retorno dentro del cierre se devuelve en la transacción () por lo que si lo devuelve
redirect()->back()
no se redirigirá inmediatamente, porque devolvió la variable que maneja la transacción.Ajustar transacción
$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;
entonces la alternativa es lanzar una variable booleana y manejar la función de redirección externa de la transacción o si necesita recuperar por qué falló la transacción, puede obtenerla desde
$e->getMessage()
adentrocatch(Exception $e){...}
fuente
Decidí dar una respuesta a esta pregunta porque creo que se puede resolver usando una sintaxis más simple que el intrincado bloque try-catch. La documentación de Laravel es bastante breve sobre este tema.
En lugar de usar try-catch, puede usar el
DB::transaction(){...}
contenedor de esta manera:// 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!']); }); };
Entonces debería ver que el usuario y el registro de registro no pueden existir el uno sin el otro.
Algunas notas sobre la implementación anterior:
return
la transacción, para que pueda utilizar laresponse()
devolución dentro de su devolución de llamada.throw
una excepción si desea que la transacción se revierta (o tenga una función anidada que lance la excepción automáticamente, como una excepción SQL desde dentro de Eloquent).id
,updated_at
,created_at
y cualesquiera otros campos están disponibles después de la creación para el$user
objeto (por la duración de esta transacción). La transacción se ejecutará a través de cualquier lógica de creación que tenga. SIN EMBARGO, todo el registro se descarta cuandoAnyException
se lanza. Esto significa que, por ejemplo, una columna de incremento automático paraid
sí se incrementa en transacciones fallidas.Probado en Laravel 5.8
fuente