2016-11-08 3 views
1

Подумайте, закажите билет в кино. Есть x количество открытых мест, когда вы приходите на сайт, я хочу зарезервировать одно из мест в течение определенного периода времени.Резервирование A Theatre Seat

У меня есть частный внутренний API и общедоступный API. Открытый API ответит на приложение, которое хочет зарезервировать место, позвонив по внутреннему API и затем разместив это место в статусе «Будущее забронировано».

Моя проблема заключается в том, что я иногда два человека заказывал одно и то же место, и это приводит к тому, что один человек вводит всю свою информацию, а затем не может завершить регистрацию.

Я попытался сделать код безопасным, но я все еще получаю нечетное дублирующее присвоение того же места.

Я звоню мой статус обновления от моего метода «Резерв» как таковой:

VisitStatusChangeResult visit_status_change_result = await ReserveSlotByLockedStatusUpdate(first_empty_seat);

это метод обновления статуса, который я пытался добавить нить Техника безопасности в помощью SemaphoreSlim:

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(); 
    } 

} 

Я пропустил что-то, где даже с SemaphoreSlim ждут, у меня могут быть два человека, хватающих одно и то же место?

+3

Вы сохраняете информацию о резервировании в базе данных? Если да, то почему это разрешено (на уровне базы данных) для такой ситуации? – Evk

+0

Да, места каждая представляют собой строку в базе данных с fk из 'VisitStatusID', для которой установлено значение« Бытие », поэтому мы знаем, что место зарезервировано до тех пор, пока клиент не забронирует место, не покинет заявку на бронирование, или они не хватит времени. – Mark

ответ

1

Во-первых, использование блокировок в памяти для обеспечения параллельного доступа к ресурсу базы данных - не очень хорошая идея - каждая база данных имеет свои собственные инструменты для таких вещей. Скорее всего, вы должны использовать оптимистический параллелизм в этом случае, примерно так:

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

Таким образом, вы знаете кто теперь бронирование это место, а также, если так случилось, что это место уже не бесплатно - это оператор вернет 0 (0 строк изменено). Вы должны проверить это и действовать соответствующим образом (уведомите клиента о том, что это место уже занято и обновлено местами).

Во-вторых, ваша блокировка не имеет никакого эффекта. Ничто не мешает двум клиентам звонить ReserveSlotByLockedStatusUpdateпоследовательно один за другим и все еще попадать в неприятности, потому что они оба зарезервируют одно и то же место (если вы не реализуете оптимистичный параллелизм, как указано выше).

+0

Спасибо, что нашли время ответить. Мы проверяем статус на сиденье для следующей попытки обновить статус перед обновлением, но это все еще может провалиться? Если это помогает, мы используем mysql. – Mark

+0

Да, потому что между вашим проверкой и обновлением строка может быть уже обновлена ​​(если вы не делаете что-то вроде блокировки строки базы данных в строке). Но если вы просто делаете очередной выбор, а затем обновляете его, это небезопасно. – Evk

+0

Так что из-за этого внешнего доступа (БД) я должен посмотреть, как справиться с этим с помощью методологий согласованности БД. Если бы я не попал в БД, я мог бы остаться в потокобезопасной операции, как я пытался? – Mark