LockModeType
JPA предоставляет оптимистические и пессимистические режимы блокировки. Их поведение зависит от транзакции, диалекта и возможностей БД.
Оптимистическая блокировка
Сущность содержит поле @Version. При обновлении Hibernate добавляет версию в условие:
update account
set balance = ?, version = version + 1
where id = ? and version = ?Если обновлено ноль строк, другой участник уже изменил запись — возникает optimistic lock exception.
OPTIMISTICпроверяет версию;OPTIMISTIC_FORCE_INCREMENTдополнительно увеличивает её;- устаревшие имена
READиWRITEявляются синонимами этих режимов.
Пессимистическая блокировка
PESSIMISTIC_READ— разделяемая блокировка, если БД её поддерживает;PESSIMISTIC_WRITE— блокировка для изменения, частоSELECT ... FOR UPDATE;PESSIMISTIC_FORCE_INCREMENT— блокировка плюс увеличение версии.
Такая блокировка удерживается до завершения транзакции. Возможны ожидание, timeout и deadlock. Порядок захвата строк должен быть единообразным.
Account account = em.find(
Account.class,
id,
LockModeType.PESSIMISTIC_WRITE
);Как выбирать
- редкие конфликты —
@Versionи повтор операции; - короткая операция с высокой конкуренцией — пессимистическая блокировка;
- инвариант по нескольким строкам — сначала спроектировать транзакцию и ограничения БД;
- внешняя сеть внутри блокировки — почти всегда плохая идея.
Вопросы для повторения
- Что обнаруживает
@Version? Потерянное обновление одной версии сущности. - Пессимистическая блокировка работает без транзакции? Нет, смысл блокировки задаёт транзакционная граница.
PESSIMISTIC_WRITEблокирует таблицу? Обычно конкретные выбранные строки, но план и СУБД могут изменить масштаб.- Что делать при optimistic conflict? Вернуть конфликт пользователю или безопасно повторить всю бизнес-операцию.
- Как уменьшить deadlock? Захватывать ресурсы в одинаковом порядке и сокращать транзакцию.
Связано: Transactional, Изоляция транзакций, Deadlock.