← Blog
Laravel
Race conditions en compra de tickets: cómo las resolví con DB::transaction y lockForUpdate()
⏱ 5 min de lectura
📅 21 de April de 2026
👁 57 vistas
El problema real que tuve en RifasSkri cuando dos usuarios compraban el mismo número al mismo tiempo, y la solución definitiva con transacciones DB.
Race Conditions en Laravel
Cuando dos usuarios intentan comprar el mismo boleto simultáneamente...
// ❌ MAL — sin protección
public function buyTicket(Request $request)
{
$ticket = Ticket::where("number", $request->number)->first();
if ($ticket->status === "available") {
$ticket->update(["status" => "sold", "user_id" => auth()->id()]);
}
}
// ✅ BIEN — con transacción y lock
public function buyTicket(Request $request)
{
DB::transaction(function () use ($request) {
$ticket = Ticket::where("number", $request->number)
->lockForUpdate()
->first();
if ($ticket->status !== "available") {
throw new \Exception("Número ya vendido");
}
$ticket->update(["status" => "sold", "user_id" => auth()->id()]);
});
}
El lockForUpdate() bloquea la fila hasta que la transacción termine.