← 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.

#laravel#database#race-conditions#transactions#mysql