En ciertas ocasiones, necesitamos realizar una serie de operaciones consecutivas, y es fundamental que todas se completen con éxito, sin que ninguna quede a medias.
Un ejemplo común es la creación de un usuario, donde es esencial que también se asignen roles y se envíe un correo de registro.
Para manejar este tipo de situaciones, se utilizan las transacciones. A continuación, presentamos un método que crea un usuario, asigna el rol, y luego envía un correo a través del método sendEmail(). Este método recibe el correo electrónico como argumento y realiza el envío correspondiente.
use Illuminate\Support\Facades\DB;
public function save(array $data)
{
try {
$user = User::create($data);
$user->syncRoles([$data['role']]);
$this->sendEmail([
'email' => $data['email'],
]);
return $user;
} catch (\Exception $e) {
throw new BadRequestException("Error al guardar nuevo usuario");
}
}
Debemos aplicar 3 métodos:
-
DB::beginTransaction();
Inicia una transacción -
DB::commit();
Confirma los cambios -
DB::rollback();
En caso de que alguna operación no se pueda realizar revertirá todos los cambios haciendo que el estado sea el mismo a antes del inicio de la transacción.
Implementando transacciones en el código anterior nos queda:
use Illuminate\Support\Facades\DB;
public function save(array $data)
{
// Iniciar la transacción
DB::beginTransaction();
try {
$user = User::create($data);
$user->syncRoles([$data['role']]);
$this->sendEmail([
'email' => $data['email'],
]);
// Confirmo la transacción
DB::commit();
return $user;
} catch (\Exception $e) {
// Si falla hago rollback
DB::rollback();
throw new BadRequestException("Error al guardar nuevo usuario");
}
}
Con esto nos aseguramos que el conjunto de operaciones se ejecuten completamente o no se ejecuten en absoluto.
Laravel también proporciona otro método mas concreto transaction
de la fachada DB. En este caso el commit
y el rollback
se realizan de forma automática. Esto es recomendable cuando la cantidad de operaciones son pocas o no requiere operaciones adicionales antes de realizar el rollback
DB::transaction(function () use($data){
$user = User::create($data);
$user->syncRoles([$data['role']]);
$this->sendEmail([
'email' => $data['email'],
]);
return $user;
});
Importante: Consideraciones del motor de base de datos
No todos los motores de almacenamiento soportan transacciones. InnoDB es un motor que sí soporta transacciones, mientras que MyISAM no lo hace. Es fundamental asegurarse de que las tablas de la base de datos estén utilizando un motor que admita transacciones para que estas funcionen correctamente.
Top comments (2)
This is a great explanation of transactions in Laravel! I especially appreciate the clear examples and the section on database engine considerations.
Thanks bro