Ответ
Да, в Hibernate для реализации оптимистичной блокировки используется специальное поле, аннотированное @Version. Этот механизм предотвращает "потерянные обновления" (lost updates) в многопользовательских средах без физической блокировки записей в БД.
Принцип работы:
- При загрузке сущности Hibernate запоминает значение поля
version. - При обновлении (
UPDATE) вWHERE-условие добавляется проверкаAND version = [запомненное_значение]. - Если версия в БД изменилась (другой поток/транзакция уже обновил запись), условие не срабатывает и количество обновленных строк = 0.
- Hibernate обнаруживает это и выбрасывает
OptimisticLockException.
Пример реализации:
@Entity
public class Account {
@Id
private Long id;
private BigDecimal balance;
@Version // Обязательно: тип Integer, Long, int, long, Timestamp
private Long version; // Hibernate будет инкрементировать это поле автоматически
// getters and setters
}
Что происходит в БД:
-- При обновлении Hibernate сгенерирует примерно такой запрос:
UPDATE account
SET balance = 1500.00, version = 2 -- версия увеличивается
WHERE id = 123 AND version = 1; -- проверка исходной версии
Преимущества перед пессимистичной блокировкой (SELECT ... FOR UPDATE):
- Высокая производительность: Нет долгих блокировок, читающие транзакции не блокируются.
- Масштабируемость: Подходит для систем с высокой конкурентностью и короткими транзакциями.
Недостаток: При конфликте приложение должно обработать исключение и повторить операцию (retry logic).