Имеется интернет магазин. Товары в нем имеют поле количество на складе. Как в ситуации, когда при покупке товара, количество которого равно 1, двумя пользователями одновременно, избежать того, что оба оплатят товар. т.к. запросы асинхронные, то простая проверка на условие равно 0 тут не поможет.
twobomb, не гребите всех под одну гребенку. На мало-мальски нагруженной системе - это вполне реальная ситуация. На системе нагруженной - такая ситуация проявляется постоянно. Но даже в случае слабо нагруженной системы, денежные операции должны быть защищены от подобных ошибок.
Vitsliputsli, Ну во первые на мало-мальски нагруженной системе это не вполне реальная ситуация, а ситация на один миллиард. Тут должны совпасть такие факторы как должен заканчиваться какой-то товар, и кнопку оформления должны нажать прям с разницей в несколько миллисекунд максимум и даже если все это сложится, то еще должно очень повезти чтобы это в коде не правильно отработало.
Во вторых люди которые делают прям сильнонагруженные системы, знают что такое транзакции и не спрашивают такие глупые вопросы на тостере.
Ну и в третьих это не связано никаким образом с обработкой денежных операций, в любом случае каждый заказ потом обрабатывает менеджер, который продвигает его дальше и если уже вы такой счасливчик и на вас сошлись звезды, вы заплатили, а товар уже зарезервирован на другого, то менеджер вам перезвонит и решит такую ситуацию сделает возврат денег или предложить выбрать другой товар, они такие вопросы решают постоянно, потому-что скорее вы не заметите что клацнули на красный цвет товара и оплатили, а потом оказалось что вы думали что выбрали зеленый, чем ситуация описанная выше.
Ну и четвертых я не сказал что нужно забивать на это и делать как попало, я сказал что просто чаще всего такими вопросами не замарачиваются фрилансеры, разрабатывая какой-нибудь мини интернет магазин. Пишите код правильно и не будет никаких проблем! (шучу, проблемы всегда будут...)
twobomb, о том и пишу, что вопрос нетривиальный, т.к. является проблемой многопоточного программирования. Но здесь добавляется тот факт, что синхронным нужно зделать запрос к серверу, что не так сложно, но приведет к тому, что при 1000 одновременных запросов сервер просто упадет - это критическое место. Поэтому и задан вопрос.
Шахмаев Анвар, да ситация как раз довольно тривиальная, ну и я бы не сказал что это даже многопоточное программирование, вот если бы вы один конекшн или контекст делили, а так все вопросы разделения решает движок бд.
И вы говорите про какой-то сервер, и что запрос к серверу сделать синхронным?
Если от клиентов, то запросы невозможно сделать синхронными. Если под сервером вы подразумаете бд, то запросы к ней и так синхронно выполяются, просто движок бд может их выстраивать в очередь, и если у вас бд падает от 1000 одновременных запросов, то у вас какая-то странная бд.
twobomb, на c# можно запросто поставить lock и клиент "висит" в ожидании при обработке запроса сервером. Использование транзакций в бд - это другое. Не думаю, что это самая простая задача, учитывая что тестировать ее не так просто.
Шахмаев Анвар, причем тут лок, если клиент делает запрос к серверу, на чем лок будет висеть? Сервер один, а клиентов много и у каждая отдельная машина.
Ну Race Condition чаще всего подразумевают когда несколько потоков используют один ресурс приложения, например переменную, а тут всетаки внешний ресурс который предоставляет свой функционал в виде транзакций, который позволяет решать такие проблемы
это называется Race Condition. Решения бывают разные, от модификации запросов с идентификатором состояния и заканчивая очередями с 1 синхронным обработчиком (RabbitMQ будет более чем достаточно).
Ну и да, транзакции применять обязательно - это единственный механизм последовательного выполнения запросов в базах данных. Если же база не поддерживает транзакции то только свои очереди
Наиболее простое решение - это блокировка данных на период выполнения бизнесовой транзакции, либо модификации запросов с идентификатором состояния. Конкретное решение будет зависить от вашей архитектуры и типа СУБД. Одного использования sql транзакций недостаточно, т.к. стандартный уровень изолированности транзакций не блокирует данные. Зачастую выбирают механизм SELECT FOR UPDATE, но его крайне не рекомендуют использовать в MySQL (во всяком случае в 5.7), да и в Oracle бывают сложности с ним.
RxR, покупка товара как синхронная операция - это единственное решение. Другое дело с запросами. Либо блокировка и ожидание, либо, как писал Иван Шумов добавление идентификатора состояния, и отказ, если состояние изменилось, либо очереди. У каждого решения есть свои минусы и плюсы. Выбирать нужно исходя из того, что вам крайне важно, а чем можно поступиться.
Vitsliputsli, зависит от СУБД. Есть например такие СУБД (firebird называется), где можно и не блокировать данные на время транзакции. Просто одна из конкурирующих транзакций при завершении получит исключение с информацией о том, что пока юзер думал, другой юзер уже все купил и данные в базе поменялись.
Фокс Йовович, это зависит не от СУБД, а от уровня изолированности транзакций. При высоких уровнях изолированности действительно можно получить нужный результат без дополнительных инструментов. Только это та же самая блокировка, пусть и на уровне СУБД. Но такие уровни изолированности применяются очень редко (практически никогда), т.к. производительность падает в пол.