#hibernate #optimistic-locking
#спящий режим #оптимистичная блокировка
Вопрос:
Интересно, какова цель optimistic locking mechanism
in Hibernate? Итак, я прочитал здесь
https://vladmihalcea.com/preventing-lost-updates-in-long-conversations / о таком сценарии:
1. Alice requests a certain product for being displayed
2. The product is fetched from the database and returned to the browser
3. Alice requests a product modification
4. The product must be updated and saved to the database
И действительно, представляется разумным использовать оптимистическую блокировку в таких сценариях.
Но управляемые или обособленные объекты отслеживаются / хранятся в контексте персистентности. Контекст сохранения ограничен процессом памяти. Означает ли это, что его можно использовать, когда существует не более одного экземпляра сервиса?
Комментарии:
1. Добавьте в список:
Adam also fetched product from DB and modified it before Alice wanted to modified
. Оптимистическая блокировка в гибернации проверяет ВЕРСИЮ СТРОКИ. Если продукт Alice имеет ту же версию, что и выбранный ею, он будет сохранен в базе данных. Если Алиса хотела сохранить продукт, но версия не совпадает с той, которую она выбрала, это вызовет исключение.2. «Означает ли это, что его можно использовать, когда существует не более одного экземпляра службы?» Как именно вы пришли к такому выводу? Оптимистичная блокировка выполняется в JPA с использованием выделенного столбца базы данных, и, конечно же, несколько экземпляров службы могут читать этот столбец, не так ли?
Ответ №1:
Основное предположение оптимистичной блокировки заключается в том, что вы не будете редактировать одну и ту же запись параллельно. Это означает, что мы не выполняем никакой явной блокировки или синхронизации. Мы загружаем данные, а затем выполняем операцию записи. Если другая транзакция записала в ту же запись, операция записи завершится ошибкой. Однако это не зависит от количества экземпляров службы. Фактически, приложение может хорошо функционировать, используя оптимистичную блокировку и произвольное количество экземпляров службы.
Рассмотрим следующий пример. Как только у вас есть объект, в котором у вас есть свойство, помеченное @Version следующим образом…
@Entity
@Table(name="test_entity")
public class TestEntity implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id", nullable = false, unique = true)
private Long id;
@Column(name = "value", nullable = true)
private String value;
@Version
@Column(nullable = false)
private Integer version;
... getters amp; setters
}
Затем код:
session.saveOrUpdate(testEntity);
session.flush();
сгенерирует следующий запрос…
update
test_entity
set
value=?,
version=?
where
id=?
and version=?
Если версия была изменена посредством параллельной транзакции либо в том же экземпляре службы, либо в отдельном экземпляре, то hibernate заметит, что обновление не повлияло ни на какие строки в базе данных, поскольку идентификатор совпал, но версия была изменена с помощью другой транзакции.
Каждый раз, когда это происходит (когда метод session.update(…) влияет на 0 строк), hibernate выдает исключение во время выполнения, чтобы указать, что оптимистическая блокировка не удалась — OptimisticLockException. Это означает, что основное соображение заключается в том, считаете ли вы, что ваши пользователи будут одновременно обновлять одну и ту же запись.
Однако, если вы используете кэш второго уровня и хотите объединить его с оптимистичной блокировкой, вам нужно будет убедиться, что вы используете правильно настроенный распределенный кэш. В противном случае кэш второго уровня означает, что вы будете загружать экземпляр из кэша второго уровня (не из контекста сохранения), а не из базы данных. В отсутствие распределенного кэша ваш кэш второго уровня, конечно, не будет иметь ни малейшего представления о том, что другой экземпляр службы обновил запись, что привело к увеличению версии. Затем, когда вы переходите к обновлению записи в базе данных (используя приведенный выше запрос), вы обновляете 0 записей и получаете исключение OptimisticLockException.