Короткий ответ
Optimistic locking добавляет в таблицу колонку версии (version/updated_at), и при обновлении запрос проверяет, что версия в БД совпадает с версией, прочитанной приложением ранее (UPDATE ... WHERE id = ? AND version = ?); если ни одна строка не обновилась — данные изменились параллельно, и приложение должно повторить операцию или сообщить о конфликте.
Как это работает подробнее
В отличие от пессимистичной блокировки (SELECT ... FOR UPDATE), здесь не удерживается блокировка строки на время «размышления» приложения — конфликт обнаруживается только в момент самой записи по несовпадению версии.
Пример кода
example.py
def update_profile(user_id: int, new_name: str, expected_version: int) -> bool:
updated = (
User.objects
.filter(id=user_id, version=expected_version)
.update(name=new_name, version=F("version") + 1)
)
return updated == 1 # False означает конфликт версий — данные изменились параллельноЧто использовать на практике
- Практика. Подходит для сценариев с низкой частотой конкурентных изменений одной строки (например, редактирование профиля); при обнаружении конфликта обычно показывают пользователю актуальные данные и просят повторить изменение.
Подводные камни
- Ошибка. Забывают увеличивать version при каждом обновлении; не проверяют количество затронутых строк после UPDATE, из-за чего «тихий» конфликт остаётся незамеченным и одно из изменений просто теряется.