Что такое Optimistic Locking (Оптимистичная блокировка) в Spring Data JPA?

Ответ

Optimistic Locking — это стратегия управления конкурентным доступом к данным, которая предполагает, что конфликты при одновременном обновлении редки. Вместо физической блокировки записи на уровне БД используется контроль версий.

Реализация через @Version:

@Entity
public class Account {
    @Id
    private Long id;
    private BigDecimal balance;

    @Version // Ключевая аннотация
    private Long version; // Поле для контроля версии
}

Как работает:

  1. Чтение: При загрузке сущности JPA сохраняет значение поля version.
  2. Обновление: При сохранении (merge/flush) JPA добавляет в WHERE-условие проверку на текущую версию:
    UPDATE account SET balance=?, version=? WHERE id=? AND version=?;
  3. Конфликт: Если количество обновлённых строк = 0 (значит, версия изменилась другим транзакцией), JPA выбрасывает OptimisticLockException.

Обработка конфликта:

@Transactional
public void transfer(Long accountId, BigDecimal amount) {
    try {
        Account acc = accountRepository.findById(accountId).orElseThrow();
        acc.withdraw(amount);
        accountRepository.save(acc);
    } catch (OptimisticLockException e) {
        // Стратегия повтора (retry) или уведомление пользователя
        throw new ConcurrentModificationException("Данные были изменены. Попробуйте снова.");
    }
}
Плюсы и минусы: Плюсы Минусы
Высокая производительность (нет долгих блокировок) Требует обработки исключений на уровне приложения
Масштабируемость Не подходит для сценариев с частыми конфликтами (например, инвентаризация последнего товара)
Избегает взаимных блокировок (deadlocks)

Альтернатива: Pessimistic Locking (LockModeType.PESSIMISTIC_WRITE), который блокирует запись на уровне БД.

Ответ 18+ 🔞

Да ты посмотри, что вытворяют эти программисты, блядь! Оптимистичная блокировка, говоришь? Ну прям как в жизни — надеемся на лучшее, а в итоге получаем по ебалу исключением!

Вот смотри, как они это выкручивают. Вместо того чтобы наглухо запирать запись в базе, как сторож-алкаш сарай на ночь, они просто ставят на неё версию, как на бутылке с самогоном. Прикол в том, что все думают, будто конфликтов не будет. Ну, как в очереди за колбасой в девяностые — все вежливые, пока не кончится последняя палка.

Вот как это в коде выглядит, не трогай:

@Entity
public class Account {
    @Id
    private Long id;
    private BigDecimal balance;

    @Version // Вот эта, блядь, волшебная палочка!
    private Long version; // Счётчик, который всех и спасает, и подставляет
}

А работает это, блядь, так:

  1. Читаем: Загрузил ты себе запись, и версию эту, сука, запомнил. Как номер билета в кассе.
  2. Пишем: Пошёл обновлять, а JPA тебе тихонько в запрос подсунула проверку:
    UPDATE account SET balance=?, version=? WHERE id=? AND version=?;

    То есть, типа, "обновлю только если версия та же, что и брал". Хитро, блядь!

  3. Пиздец: А если строк обновлённых ноль — значит, пока ты тут умничал, кто-то уже успел твою запись подправить и версию увеличить. И тебе в ответ — жирный OptimisticLockException прямо в ебальник!

Ловить это безобразие надо как-то так:

@Transactional
public void transfer(Long accountId, BigDecimal amount) {
    try {
        Account acc = accountRepository.findById(accountId).orElseThrow();
        acc.withdraw(amount);
        accountRepository.save(acc);
    } catch (OptimisticLockException e) {
        // Вот тут либо по-умному — перепробовать, либо просто пользователю сказать, что всё просрал
        throw new ConcurrentModificationException("Данные были изменены. Попробуйте снова.");
    }
}

Ну и как всегда, есть свои плюсы и минусы, ёпта:

Что хорошего Что за дерьмо
Быстро, блокировок долгих нет Надо эти ебучие исключения ловить самому
Масштабируется легко Если все лезут в одну запись — будет пиздец и сплошные повторы
Deadlock'ов не будет (в теории) Для вещей типа "последний товар на складе" — вообще не катит

А есть же ещё, блядь, и пессимистичный подход! Тот самый PESSIMISTIC_WRITE. Это когда ты сходу хватаешь запись, вешаешь на неё замок на уровне базы и не пускаешь никого, пока сам не отойдёшь. Как собака на сене, только с SQL-запросом. Надёжно, но медленно и можно всех заблокировать. Выбирай, что тебе больше по душе — верить в хорошее и получать по щам, или никому не верить и сидеть на замке самому.