2016-11-08 1 views
1

Denken Sie daran, ein Ticket für einen Film zu buchen. Es gibt x Anzahl der offenen Plätze, wenn Sie auf die Website kommen, möchte ich einen der Plätze für einen bestimmten Zeitraum reservieren.Reservieren eines Theaterplatzes

Ich habe eine private interne API und eine öffentliche API. Die öffentliche API würde auf die Anwendung reagieren, die versucht, einen Sitzplatz zu reservieren, indem sie die interne API aufruft und diesen Platz dann in einen "Being Booked" Status setzt.

Mein Problem ist, dass ich gelegentlich zwei Personen den gleichen Platz buchen, und das führt dazu, dass eine Person alle ihre Informationen eingeben, und dann nicht in der Lage, ihre Registrierung zu beenden.

Ich habe versucht, meinen Code Thread sicher zu machen, aber immer noch die ungerade doppelte Zuordnung des gleichen Sitzes.

Ich rufe meinen Status-Update von meiner "Reserve" Methode als solche:

VisitStatusChangeResult visit_status_change_result = await ReserveSlotByLockedStatusUpdate(first_empty_seat);

dies ist die Status-Update-Methode, die ich versucht habe durch die Verwendung SemaphoreSlim Thread saftey hinzuzufügen:

private static SemaphoreSlim m_ReserveOnlineSlotStatusUpdateSemaphore = new SemaphoreSlim(initialCount: 1, maxCount: 1); 


private async Task<VisitStatusChangeResult> ReserveSlotByLockedStatusUpdate(VisitQueryResult first_empty_seat) 
{ 
    await m_ReserveOnlineSlotStatusUpdateSemaphore.WaitAsync(); 

    try 
    { 
    return await ChangeStatus(new VisitStatusUpdateModel 
    { 
     VisitID = first_empty_seat.ID, 
     CurrentVisitStatusID = first_empty_online_visit.VisitStatusID, 
     NewVisitStatusID = (int)VisitStatuses.BeingBooked 
    }); 
    } 
    finally 
    { 
    m_ReserveOnlineSlotStatusUpdateSemaphore.Release(); 
    } 

} 

Fehle ich etwas, wo sogar mit dem SemaphoreSlim zwei Leute auf dem gleichen Platz sitzen können?

+3

Speichern Sie Reservierungsinformationen in der Datenbank? Wenn ja, warum ist es (auf Datenbankebene) möglich, dass eine solche Situation eintritt? – Evk

+0

Ja, die Plätze sind jeweils eine Zeile in einer Datenbank mit einem fk von 'VisitStatusID', was auf" BeingBooked "eingestellt ist, also wissen wir, dass Platz reserviert ist, bis der Kunde den Platz reserviert hat, den Buchungsantrag verlässt, oder sie keine Zeit mehr haben. – Mark

Antwort

1

Erstens, die Verwendung von speicherinternen Sperren zum Schutz des parallelen Zugriffs auf die Datenbankressource ist keine gute Idee - jede Datenbank hat ihre eigenen Tools für solche Dinge. Wahrscheinlich müssen Sie Parallelität in diesem Fall benutzen, etwa wie folgt aus:

update Visit set VisitStatusID = BeingBooked, ClientID = CurrentClientID where VisitStatusID = Free 

So wissen Sie die jetzt diesen Sitz buchen, und auch, wenn so passiert, dass dieser Platz schon nicht frei ist - dies Die Anweisung gibt 0 zurück (0 Zeilen geändert). Sie sollten dies überprüfen und entsprechend handeln (Kunden benachrichtigen, dass dieser Platz bereits belegt ist und die Plätze auffrischen).

Zweitens hat Ihr Schloss sowieso keine Wirkung. Nichts verhindert für zwei Clients, ReserveSlotByLockedStatusUpdateder Reihe nach, eine nach der anderen, und immer noch in Schwierigkeiten geraten, weil sie beide den gleichen Platz reservieren (es sei denn, Sie implementieren optimistische Nebenläufigkeit wie oben).

+0

Vielen Dank, dass Sie sich die Zeit genommen haben zu antworten. Wir überprüfen den Status auf dem Sitzplatz für den nächsten Versuch, den Status vor der Aktualisierung zu aktualisieren, aber dies kann immer noch durchfallen? Wenn es hilft, verwenden wir mysql. – Mark

+0

Ja, denn zwischen Ihrer Überprüfung und dem Update wurde die Zeile möglicherweise bereits aktualisiert (es sei denn, Sie führen z. B. eine Datenbankzeilensperre für die fragliche Zeile durch). Aber wenn Sie nur regelmäßig wählen, gefolgt von Update - es ist nicht sicher. – Evk

+0

Also wirklich wegen dieses externen Zugriffs (der DB) sollte ich versuchen, dies über DB-Methoden zu bewältigen. Wenn ich nicht die DB treffen würde, könnte ich in einer Thread-sicheren Operation bleiben, wie ich es versucht habe? – Mark

Verwandte Themen