Что такое версия (version) в Hibernate и как она используется для оптимистичной блокировки
Что проверяют
Понимаете ли вы, что оптимистичная блокировка ничего не блокирует, а проверяет актуальность данных в момент записи, и умеете ли обрабатывать её отказ. Заодно проверяют, читали ли вы сгенерированный SQL, а не только аннотации.
Как отвечать
Поле, помеченное аннотацией @Version, Hibernate ведёт сам: читает вместе с сущностью, подставляет в условие обновления и увеличивает. Запрос выглядит так:
update product set name = ?, version = 6 where id = ? and version = 5Если обновлено ноль строк, значит кто-то успел записать раньше, и провайдер бросает исключение о потерянном обновлении. В современных версиях аннотация живёт в пакете jakarta.persistence, в проектах постарше в javax.persistence.
@Entity
public class Product {
@Id private Long id;
private String name;
@Version private Integer version;
}Тип поля может быть целочисленным или временной меткой. Счётчик надёжнее: метка времени зависит от разрешения часов и их расхождения между узлами.
Отдельно скажите про поведение: строка не блокируется, конкурент спокойно читает и пишет свою версию, а конфликт всплывает при сбросе изменений в базу, то есть часто в самом конце транзакции. Обработка одна: открыть новую транзакцию, перечитать данные и повторить бизнес-операцию. Если конфликты частые, дешевле пессимистичная блокировка на чтение для обновления.
Где спотыкаются
Правят версию руками, в коде или батчем в SQL. Поле принадлежит провайдеру, ручное вмешательство ломает проверку и возвращает тихую потерю обновлений, которую невозможно поймать тестом.
Считают, что версия закрывает все изменения сущности. Обновление в обход контекста (нативный запрос, массовый апдейт) версию не трогает, изменение только дочерней коллекции тоже может её не поднять. Для таких случаев есть принудительное повышение версии при блокировке.
Ловят исключение и пробуют сохранить ещё раз тем же контекстом. После неудачного сброса контекст непригоден, а объект в памяти хранит устаревшее состояние. Повтор возможен только с новой транзакцией и свежим чтением.