Что такое оптимистичная блокировка (оптимистичный контроль параллелизма)?

Ответ

Оптимистичная блокировка (Optimistic Locking) — это стратегия управления конкурентным доступом к данным, основанная на предположении, что конфликты между транзакциями происходят редко. Вместо физической блокировки записей на время транзакции используется механизм проверки версии данных при их обновлении.

Принцип работы:

  1. Транзакция читает данные вместе с их версией (например, числовым полем version или меткой времени).
  2. Производятся изменения в памяти.
  3. При попытке сохранения (UPDATE) в запрос добавляется условие WHERE version = [прочитанное_значение].
  4. Если за это время данные не изменились (версия совпадает), обновление проходит успешно, и версия инкрементируется.
  5. Если другая транзакция уже обновила данные (версия изменилась), условие WHERE не срабатывает, и текущая транзакция завершается с ошибкой (например, OptimisticLockException).

Реализация в JPA/Hibernate с аннотацией @Version:

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

    @Version // Поле автоматически управляется фреймворком
    private Long version;
}
Плюсы и минусы: Плюсы Минусы
Высокая производительность (отсутствуют блокировки, препятствующие чтению). Требует обработки конфликтов (повторные попытки или уведомление пользователя).
Масштабируемость. Не подходит для сценариев с очень высокой конкуренцией за одни и те же данные.
Избегает взаимных блокировок (deadlocks).

Ответ 18+ 🔞

А, оптимистичная блокировка, говоришь? Ну это как в жизни, блядь. Представь: ты пришёл в магазин, последний пирожок с вишней на полке лежит. Ты его видишь, запоминаешь, что он там, и идёшь за деньгами в машину. А пока ты шёл, какой-то хитрожопый ушлёпок уже этот пирожок схватил и сожрал. Ты возвращаешься, а там пусто. Вот тебе и весь принцип, в рот меня чих-пых!

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

Как это технически выглядит, ёпта:

  1. Ты читаешь запись из базы. Допустим, account.balance = 1000 и account.version = 5. Запоминаешь эту пятёрку, как святую.
  2. Ты там у себя в коде эту тысячу меняешь, допустим, отнимаешь сто.
  3. И вот, сука, ключевой момент! Когда идёшь сохранять, пишешь в базу не просто UPDATE account SET balance = 900 WHERE id = 1, а UPDATE account SET balance = 900, version = 6 WHERE id = 1 AND version = 5.
  4. Если за это время никто не трогал запись, версия совпадёт, обновление пройдёт, и версия станет 6. Всё, пирожок твой.
  5. А если пока ты считал, какой-то пидарас шерстяной уже успел снять деньги и обновил версию до 6, твоё условие WHERE version = 5 нихуя не найдёт, и строки не обновится. Твоя транзакция, понимаешь, накрывается медным тазом с криком OptimisticLockException. Иди, чувак, теперь думай: то ли пользователю сказать «извини, обнови страницу», то ли заново логику выполнить.

В коде на JPA это вообще красота, один аннотацией делается:

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

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

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

А теперь плюсы и минусы, как есть:

Что хорошо, ёбта? Что плохо, нахуй?
Скорость, блядь! Никаких физических блокировок, которые всё тормозят. Читать могут все, когда угодно. Конфликты надо обрабатывать. Не получилось с первого раза — пиши логику повтора или выводи пользователю «ой, данные устарели, обнови».
Масштабируется овердохуища. Тысячи потоков могут читать данные без проблем. Для драк не годится. Если у тебя десять потоков бьются за обновление одной и той же строчки каждую секунду, то это будет пиздец, а не оптимизм. Сплошные исключения и повторные попытки.
Мёртвых хваток (deadlock) не бывает. Потому что никто никого не ждёт и не блокирует.

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