CÓMO MANEJAR TRANSACCIONES EN LARAVEL
Una transacción es un grupo de operaciones SQL que se ejecutan como una unidad atómica:- Todo o nada (Atomicity).
- Son consistentes (Consistency).
- Aisladas entre sí (Isolation).
- Duraderas una vez confirmadas.
use Illuminate\Support\Facades\DB;
DB::transaction(function () {
$order = Order::create([
'user_id' => $user->id,
'total' => $request->total,
'status' => 'pending',
]);
foreach ($request->products as $item) {
OrderItem::create([
'order_id' => $order->id,
'product_id' => $item['id'],
'quantity' => $item['qty'],
'price' => $item['price'],
]);
// Reducir stock (¡crítico!)
Product::where('id', $item['id'])->decrement('stock', $item['qty']);
}
});
- Si cualquier línea falla se realiza rollback automático.
- Código limpio y legible.
- Laravel maneja el commit y rollback por ti.
// Cuando necesitas controlar el rollback manualmente
use Illuminate\Support\Facades\DB;
try {
DB::beginTransaction();
$userId = DB::table('users')->insertGetId([
'name' => 'Ana',
'email' => 'ana@example.com'
]);
DB::table('profiles')->insert([
'user_id' => $userId,
'bio' => 'Diseñadora'
]);
DB::commit();
} catch (\Exception $e) {
DB::rollBack();
// Manejar error
echo "Error: " . $e->getMessage();
}
Mejores prácticas
- Transacciones cortas: Nada de llamadas HTTP, emails, resize de imágenes o jobs pesados dentro de la transacción:
$order = null; DB::transaction(function () use (&$order) { $order = Order::create([...]); // solo DB }); // Fuera de la transacción ProcessPaymentJob::dispatch($order); - Evitar transacciones muy largas ya que se producen bloqueos y timeouts en las bases de datos.
- Usa pessimistic locking cuando sea necesario:
DB::transaction(function () { $product = Product::lockForUpdate()->find($id); // ... ahora nadie más puede modificar este registro }); - Devoler valores desde DB::transaction()
$newOrder = DB::transaction(function () { $order = Order::create([...]); // ... return $order; }); - No abusar ya que un un solo INSERT/UPDATE no necesita transacción ya es atómico.