32. Какие шесть режимов блокировок (lock modes) описаны спецификации JPA (или какие есть значения у enum LockModeType в JPA)?

32. Какие шесть режимов блокировок (lock modes) описаны спецификации JPA (или какие есть значения у enum LockModeType в JPA)?

UNKNOWN

У JPA есть шесть режимов блокировок (lock modes), перечислим их в порядке увеличения надежности (от самого ненадежного  и быстрого, до самого надежного и медленного):

  1. NONE — без блокировки.
  2. OPTIMISTIC (или  синоним  READ,  оставшийся  от  JPA  1)  — оптимистическая блокировка.
  3. OPTIMISTIC_FORCE_INCREMENT (или синоним WRITE, оставшийся от JPA 1) —  оптимистическая  блокировка  с  принудительным  увеличением  поля версионности.
  4. PESSIMISTIC_READ — пессимистичная блокировка на чтение.
  5. PESSIMISTIC_WRITE — пессимистичная блокировка на запись (и чтение).
  6. PESSIMISTIC_FORCE_INCREMENT — пессимистичная блокировка на запись (и чтение) с принудительным увеличением поля версионности.

Оптимистичное блокирование

Оптимистичный  подход  предполагает,  что  параллельно  выполняющиеся транзакции редко обращаются к одним и тем же данным и позволяет им спокойно и свободно выполнять любые чтения и обновления данных. Но при окончании транзакции производится проверка, изменились ли данные в ходе выполнения данной транзакции и,  если  да,  транзакция  обрывается  и  выбрасывается  исключение.

Оптимистичное блокирование  в  JPA  реализовано  путём  внедрения  в  сущность  специального  поля версии:

@Entity

public class Company extends AbstractIdentifiableObject {

    @Version

    private long version;

    @Getter

    @Setter

    private String name;

    @Getter

    @Setter

    @ManyToMany(mappedBy = \"workingPlaces\")

    private Collection<Person> workers;

}

Поле, аннотирование @Version, может быть целочисленным или временнЫм.

При завершении транзакции, если сущность была оптимистично заблокирована, будет проверено, не изменилось ли значение @Version кем-либо ещё, после того как данные были  прочитаны,  и,  если  изменилось,  будет  выкинуто  OptimisticLockException. 

Использование этого поля позволяет отказаться от блокировок на уровне базы данных и сделать всё на уровне JPA, улучшая уровень конкурентности.

JPA поддерживает два типа оптимистичной блокировки:

  1. LockModeType.OPTIMISTIC  —  блокировка  на  чтение,  которая  работает,  как описано  выше:  если  при  завершении  транзакции  кто-то  извне  изменит  поле @Version,  то  транзакция  автоматически  будет  откачена  и  будет  выброшено OptimisticLockException.
  2. LockModeType.OPTIMISTIC_FORCE_INCREMENT  —  блокировка  на  запись. Ведёт себя как и блокировка на чтение, но при этом увеличивает значение поля @Version.

Обе блокировки ставятся путём вызова метода lock() у EntityManager, в который передаётся сущность, требующая блокировки и уровень блокировки:

EntityManager em = entityManagerFactory.createEntityManager();

em.lock(company1, LockModeType.OPTIMISTIC);

em.lock(company2, LockModeType.OPTIMISTIC_FORCE_INCREMENT);

Блокировка будет автоматически снята при завершении транзакции, снять её до этого вручную невозможно.

Пессимистичное блокирование

Пессимистичный  подход  напротив,  ориентирован  на  транзакции,  которые постоянно  или  достаточно  часто  конкурируют  за  одни  и  те  же  данные  и  поэтому блокирует  доступ  к  данным  превентивно,  в  тот  момент  когда  читает  их.  Другие транзакции останавливаются, когда пытаются обратиться к заблокированным данным и  ждут  снятия  блокировки  (или  кидают  исключение). Пессимистичное  блокирование выполняется на уровне базы и поэтому не требует вмешательств в код сущности. Так же,  как  и  в  случае  с  оптимистичным  блокированием,  поддерживаются  блокировки чтения и записи:

  • LockModeType.PESSIMISTIC_READ — данные блокируются в момент чтения и это  гарантирует,  что  никто  в  ходе  выполнения  транзакции  не  сможет  их изменить. Остальные транзакции, тем не менее, смогут параллельно читать эти данные.  Использование  этой  блокировки  может  вызывать  долгое  ожидание блокировки или даже выкидывание PessimisticLockException.
  • LockModeType.PESSIMISTIC_WRITE — данные блокируются в момент записи и никто с момента захвата блокировки не может в них писать и не может их читать до  окончания  транзакции,  владеющей  блокировкой.  Использование  этой блокировки может вызывать долгое ожидание блокировки.

Кроме  того,  для  сущностей  с  полем,  аннотированным  @Version,  существует третий вариант пессимистичной блокировки:

  • LockModeType.PESSIMISTIC_FORCE_INCREMENT  —  ведёт  себя  как  LockModeType.PESSIMISTIC_WRITE,  но  в  конце  транзакции  увеличивает значение поля @Version, даже если фактически сущность не изменилась.

Накладываются  пессимистичные  блокировки  так  же  как  и  оптимистичные, вызовом метода lock():

em.lock(company1, LockModeType.PESSIMISTIC_READ);

em.lock(company2, LockModeType.PESSIMISTIC_WRITE);

em.lock(company3, LockModeType.PESSIMISTIC_FORCE_INCREMENT);

Снимаются они тоже автоматически, по завершению транзакции.

Следующие  публичные  методы  EntityManager-а  могут  использоваться  для наложения блокировок:

void lock(Object entity, LockModeType lockMode)

void lock(Object entity, LockModeType lockMode, Map<String, Object>  properties)

<T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode)

<T> T find(Class<T> entityClass, Object primaryKey, LockModeType

lockMode, Map<String, Object> properties)

void refresh(Object entity, LockModeType lockMode)

void refresh(Object entity, LockModeType lockMode, Map<String, Object> properties)

Помимо  вышеуказанных  методов,  в  Query  API  также  есть  методы  для определения блокировок.


Предыдущий вопрос: 31. Для чего нужна аннотация @Transient?

Следующий вопрос: 33. Какие два вида кэшей (cache) вы знаете в JPA и для чего они нужны?

Все вопросы по теме: список

Все темы: список

Вопросы/замечания/предложения/нашли ошибку: напишите мне

Report Page