В каких сценариях выгодно использовать оптимистическую блокировку (Optimistic Lock)?

«В каких сценариях выгодно использовать оптимистическую блокировку (Optimistic Lock)?» — вопрос из категории Базы данных, который задают на 10% собеседований Java Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Оптимистическая блокировка выгодна в высокопроизводительных приложениях с низкой вероятностью конфликта параллельных изменений одних и тех же данных (read-heavy или low-contention сценарии).

Принцип работы: Механизм не блокирует запись на уровне БД. Вместо этого каждая сущность имеет поле-версию (обычно @Version). При чтении запоминается значение версии. При попытке обновления в WHERE-условие добавляется проверка, что версия не изменилась. Если она изменилась (значит, данные уже обновили), выбрасывается OptimisticLockException.

Пример реализации в JPA:

@Entity
public class BankAccount {
    @Id
    private Long id;
    private BigDecimal balance;
    @Version
    private Long version; // Hibernate автоматически увеличивает эту версию при каждом UPDATE
}

// В сервисе. Если два потока попытаются обновить один счет,
// второй получит OptimisticLockException.
@Transactional
public void withdraw(Long accountId, BigDecimal amount) {
    BankAccount account = entityManager.find(BankAccount.class, accountId);
    account.setBalance(account.getBalance().subtract(amount));
    // При коммите выполнится SQL: UPDATE account SET balance=?, version=? 
    // WHERE id=? AND version=? (проверка старой версии)
}

Преимущества:

  • Высокая пропускная способность (throughput): Отсутствуют блокировки, читающие транзакции не ждут.
  • Улучшенная масштабируемость.

Недостатки и требования:

  • Необходима обработка конфликтов (retry-логика или уведомление пользователя).
  • Плохо подходит для сценариев с высокой конкуренцией за запись (high-contention), например, обновление счётчика последнего номера заказа. В таких случаях лучше подходит пессимистическая блокировка (SELECT ... FOR UPDATE).