Оптимальная блокировка и масштабируемость

#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.