Какие варианты решения проблемы одновременного редактирования одной записи несколькими пользователями?
Что проверяют
Знаете ли вы проблему потерянного обновления и умеете ли выбрать между оптимистической и пессимистической блокировкой под сценарий. Следом обычно спрашивают, как это выглядит в JPA и что увидит второй пользователь, когда его изменения не сохранятся.
Как отвечать
Начните с проблемы: двое открыли карточку заказа, оба сохраняют, и правки первого молча перезаписываются. Одного @Transactional мало: транзакция не длится, пока человек думает над формой.
- оптимистическая блокировка: поле с
@Versionв сущности. Hibernate добавляет вUPDATEусловиеWHERE version = ?и увеличивает версию. Если строку уже изменили, обновится 0 строк и прилетитOptimisticLockException, в Spring этоOptimisticLockingFailureExceptionи его подклассы. Версия должна доехать до клиента и вернуться с формой, в REST удобно черезETagиIf-Matchс ответом409или412; - пессимистическая блокировка:
@Lock(LockModeType.PESSIMISTIC_WRITE)в репозитории Spring Data, в SQL этоSELECT ... FOR UPDATE. Живёт только внутри транзакции, поэтому годится для коротких операций вроде списания остатка, а не для редактирования в форме. Задайте таймаут ожидания блокировки; - блокировка на уровне приложения: поля
locked_byиlocked_until, как «документ открыт другим пользователем». Обязательно с истечением срока; - атомарный
UPDATE:SET balance = balance - ?без цикла «прочитал, изменил, записал» в приложении, когда меняется счётчик, а не вся запись; - слияние по полям или совместное редактирование (OT, CRDT): для документов, где конфликты объединяют, а не отклоняют.
Для обычных бизнес-форм стандартный выбор это @Version плюс понятное сообщение о конфликте.
Где спотыкаются
Предлагают synchronized. Он работает внутри одной JVM, а приложение обычно запущено в нескольких экземплярах.
Читают сущность заново перед сохранением и копируют в неё поля из формы. Версия всегда свежая, проверка ничего не ловит.
Ловят OptimisticLockException и тихо повторяют сохранение. Для фоновых задач повтор уместен, а правки пользователя так снова затираются: ему нужно показать конфликт.