DB::transaction()
en Laravel
El método DB::transaction()
acepta un closure (función anónima) que encapsula las operaciones a ejecutar dentro de la transacción. Si el closure se ejecuta sin errores, la transacción se confirma (commit
). Si ocurre una excepción o error, la transacción se revierte (rollback
).
use Illuminate\Support\Facades\DB;
DB::transaction(function () {
DB::table('users')->update(['active' => false]);
DB::table('orders')->delete();
});
En este ejemplo, ambas operaciones (update
y delete
) se ejecutan como parte de una transacción. Si alguna falla, ninguno de los cambios se aplicará en la base de datos.
DB::transaction()
1. Transacción con múltiples consultas:
Supongamos que necesitas actualizar el saldo de un usuario y registrar la transacción en otra tabla. Si alguna de las operaciones falla, no se aplican los cambios:
DB::transaction(function () use ($userId, $amount) {
DB::table('users')
->where('id', $userId)
->decrement('balance', $amount);
DB::table('transactions')->insert([
'user_id' => $userId,
'amount' => $amount,
'type' => 'withdrawal',
'created_at' => now(),
'updated_at' => now()
]);
});
Si, por ejemplo, la inserción en la tabla transactions
falla, el saldo del usuario no se verá afectado.
2. Manejo de excepciones manualmente dentro de la transacción:
Si necesitas capturar errores específicos dentro de la transacción, puedes usar un bloque try-catch
:
try {
DB::transaction(function () use ($orderData) {
DB::table('orders')->insert($orderData);
DB::table('inventory')
->where('product_id', $orderData['product_id'])
->decrement('stock', $orderData['quantity']);
});
} catch (\Exception $e) {
// Manejo de error
return back()->with('error', 'Hubo un problema con la transacción.');
}
Si alguna consulta falla, DB::transaction()
lanza una excepción, permitiéndote gestionar el error como consideres.
3. Anidar transacciones (DB::beginTransaction
y DB::commit
):
Laravel también permite el uso de DB::beginTransaction()
, DB::commit()
y DB::rollback()
manualmente:
DB::beginTransaction();
try {
DB::table('users')->update(['active' => false]);
DB::table('orders')->delete();
DB::commit(); // Confirmar la transacción
} catch (\Exception $e) {
DB::rollback(); // Revertir si hay un error
throw $e; // Lanzar la excepción nuevamente para gestionarla
}
Esto permite un control más granular en situaciones complejas donde se deben gestionar transacciones en varias capas del código.
4. Retornar valores desde una transacción:
Puedes devolver resultados dentro de un DB::transaction()
:
$result = DB::transaction(function () {
$user = DB::table('users')->where('email', 'john@example.com')->first();
DB::table('log')->insert(['user_id' => $user->id, 'action' => 'login']);
return $user;
});
echo $result->name;
Aquí, el valor retornado desde el closure ($user
) se asigna a $result
solo si la transacción se completa con éxito.
5. Forzar un rollback
manualmente:
Si necesitas revertir una transacción sin que ocurra una excepción, puedes usar DB::rollBack()
dentro del closure:
DB::transaction(function () {
DB::table('users')->update(['active' => false]);
// Condición personalizada para revertir
if (DB::table('orders')->count() < 1) {
DB::rollBack();
}
});
Esto revertirá la transacción sin necesidad de lanzar una excepción.
Para más información sobre el uso de transacciones en Laravel, consulta la documentación oficial de Laravel.
Jorge García
Fullstack developer