Приходилось ли решать проблемы конкурентного доступа к данным в многопользовательской среде?
Что проверяют
Понимаете ли вы, что в многопользовательском приложении гонка идёт не за объектом в памяти, а за строкой в базе. Средства языка спросят заодно, но ответ, состоящий только из них, засчитывают как неверный.
Как отвечать
Назовите сценарий: двое открыли запись, каждый поправил своё поле, второй сохранил и затёр чужое изменение. Уровень изоляции по умолчанию такое не ловит, потому что между чтением и записью проходит время, а решение принимается в приложении.
Разложите средства по ситуациям.
- Оптимистичная блокировка. Поле версии, обновление с условием на него, при расхождении исключение и дальше либо повтор, либо честное сообщение, что данные успели измениться. Подходит, когда столкновения редки.
- Атомарное обновление. Один запрос, который сам считает и сам проверяет: списание с условием на достаток остатка, а потом проверка числа затронутых строк. Читать заранее ничего не нужно.
- Пессимистичная блокировка. Явный захват строки на время изменения и обязательный таймаут ожидания. Берут, когда пересчёт сложный, а столкновения частые.
- Ограничение в схеме. Уникальный индекс и вставка с разрешением конфликта надёжнее проверки «а нет ли уже такой записи»: между проверкой и вставкой влезает соседний запрос.
Средства языка вроде атомарных типов и блокировок упомяните отдельно, оговорив, что они координируют потоки внутри одного процесса.
Где спотыкаются
Ставят блокировку на метод сервиса и считают вопрос закрытым. Экземпляров приложения несколько, блокировка у каждого своя, гонка остаётся. Заодно поток простаивает на походе в базу, и пропускная способность падает без всякой пользы.
Не обрабатывают столкновение. Оптимистичная блокировка означает, что исключение однажды прилетит, это штатный ход событий. Если его не поймать, пользователь увидит страницу ошибки вместо предложения обновить форму, а правка, которую можно было повторить, потеряется.
Ловят взаимоблокировки и не понимают откуда. Разные места кода берут одни и те же строки в разном порядке, либо захваченная строка ждёт ответа внешнего сервиса. Порядок захвата фиксируют, таймауты выставляют, а долгие вызовы выносят за границу транзакции.