Можно ли использовать версионирование или временные метки для реализации блокировки
Что проверяют
Понимаете ли вы оптимистичную блокировку: как она устроена на уровне SQL, чем версия лучше временной метки и что делать, когда конфликт всё-таки случился. Следом обычно спрашивают, когда оптимистичная блокировка хуже пессимистичной.
Как отвечать
Да, это и есть оптимистичная блокировка. Строку никто не держит на время работы, конфликт обнаруживается в момент записи:
UPDATE account SET balance = ?, version = version + 1 WHERE id = ? AND version = ?
Если обновилось 0 строк, запись уже кто-то изменил после вашего чтения. В JPA это делает поле с @Version: Hibernate сам добавляет условие и инкремент, а при конфликте бросает OptimisticLockException, Spring оборачивает его в ObjectOptimisticLockingFailureException.
Версия или метка:
- числовая версия (
long,int): монотонна и не зависит от часов. Выбор по умолчанию; - временная метка: допустима, JPA разрешает
@VersionнаTimestamp, но два обновления в пределах точности часов получат одно значение, и конфликт пройдёт незамеченным. Плюс расхождение часов между узлами.
С конфликтом два пути: повторить операцию, перечитав данные (например, через @Retryable), или вернуть клиенту 409. В REST версию удобно отдавать как ETag и принимать обновление с If-Match, при несовпадении отвечая 412.
Когда не подходит: при частых конфликтах на горячей строке (остаток на складе) повторы съедают выигрыш. Там честнее пессимистичная блокировка SELECT ... FOR UPDATE, в Spring Data это @Lock(LockModeType.PESSIMISTIC_WRITE), или атомарный UPDATE ... SET qty = qty - 1 WHERE qty > 0.
Где спотыкаются
Теряют версию между запросами. Пользователь открыл форму, а сервер при сохранении заново читает сущность и применяет изменения. Версия всегда свежая, и конфликт с тем, что видел пользователь, не ловится. Версия должна приехать от клиента.
Обновляют данные массовым JPQL UPDATE или нативным SQL и ждут, что @Version сработает. Такие запросы идут мимо механизма, версию нужно менять вручную.
Называют временные метки «надёжнее при частых конфликтах». Всё наоборот: при частых конфликтах нужна пессимистичная блокировка, а метка только добавляет риск пропустить конфликт.